Oddbean new post about | logout
 @utxo the webmaster 🧑‍💻 

cc @hzrd149 see blossom config feedback reqd for ios 
 I meant to say “any haven video” here not blossom 
 Ok I'll add  
 https://pkg.go.dev/net/http#ServeContent - this is what you are looking for (it will handle partial byte ranges and all mentioned headers). 
 but AFAIK, this needs to be done on khatru, because it does not expose the required objects. that's why i involved @fiatjaf in the thread. 
 Try to replace `io.Copy` with `http.ServeContent` and see what happens (you can fork Khatru and use go to replace khatru dependency in Haven, this is how I tested all of the CORS stuff before) 
 i'll try it tomorrow. thanks a lot! 
 I thought it was because you liked me. 
 I DO like you, the bug was just an excuse ;) 
 this worked wonders! I'll keep testing it and submit a pull request by tomorrow.

the changes were a little more complex than just adding a call to ServeContent (they always are) but i think i managed to get everything right. see here: https://github.com/fiatjaf/khatru/compare/master...girino:khatru:master

(there is still some debug "prints" in there, i'll remove them before the pull request) 
 Looking good! If you’re open to a small suggestion, and if fiatjaf doesn’t mind introducing some early-stage backwards-incompatible changes to khatru's Blossom’s API, I think you could simplify things by changing the return type here https://github.com/fiatjaf/khatru/blob/76ecf4f7914a93b7ec4f0cc0c823304a7402adab/blossom/server.go#L18 to `io.ReadSeeker`. This would allow you to eliminate the `io.Copy` fallback code and the `Content-Type` handling, as `http.ServeContent` also takes care of  that for you. It even handles ETags and cache-related headers, so I’d expect your patch to significantly improve things for all clients—not just iOS. Well done! 
 i thought about that, but was afraid it would break other people code... that's up to @fiatjaf... what do you think? 
 already one happy customer:

nostr:nevent1qgs0n4lskfcmtwcea4qqmzawacwz9tp6t0ju7gx625secjffu53es7sqyr7vhrfe20ay56kh9quexcjwf7zz848jumwj7a9s4v27308v070eygkz0gl 
 If you break other people’s code with backwards incompatible things, kindly start a tracker here: 

https://github.com/nostrability/nostrability 
 If it helps, it use to return `[]byte` and khatru Blossom's API own example was broken until a couple of weeks ago. It's ultimately Fiatjaf's decision of course, but, from my perspective, feel free go for it. 
 i'll submit a pull request as it is now (without the debug prints), and then try the non backward compatible change and see how it goes.  
 #nostrdam was fun.
That moment of time when the future happened.
@Tanja was there as well, along with @Ian and @nextblockcoffee 

The butterflies conga. 
At least the entanglement answer the most common question of how do you know #nostr. https://image.nostr.build/d45e839adc02c507bf50c174677d3c992cce0ac5e46513ea8b1be46dfb878f45.jpg  
 Unexpected to have the science department to hold the knife

Public transport science department of expensive fireworks by the word on the street https://image.nostr.build/e44271c4e0ecd555d2f5307a98fdb8a7b42ab5d511f59eae3863f1a88b18ee0d.jpg  
 I didn't know IOS required range requests for videos to work but i guess it makes sense

right now the blossom spec does not mention anything about content-length or accept-ranges but it might be good to add it, thoughts? 
 @utxo the webmaster 🧑‍💻 wdyt 
 If iOS requires it we basically have no choice  
 https://github.com/hzrd149/blossom-server/issues/16 @hzrd149 not sure if this is the right repo 
 I think that by specs he meant this one: https://github.com/hzrd149/blossom

But if the reference blossom server is not handling range requests / partial content the issue above is also valid. 
 Thanks, good point. Added ticket there so @hzrd149 can be reminded in more than one place 💪 
 fwiw im not sure if it is the issue, its just the biggest thing i saw that was different between the headers of the server responses. Would be good to know which header specifically is the issue, assuming both servers are returning the same data and there isn’t some other subtle issue. 
 It was indeed the issue, already fixed and tested by Girino and PR submitted to khatru upstream. (Check rest of this thread) 
 i wouldn't be so bold, since i din't mess directly with the headers. I just used a different API http.ServeContent, that handles the headers for me. It might any other header handled by this API that we were not aware of. We should conduct tests manually setting headers to check which one is the one required by iOS.

or simply leave it be, and document that videos might not work in iOS without extra headers, and let the devs fend for themselves. 
 It’s probably in the apple docs somewhere but im too lazy to find it 
 https://stackoverflow.com/questions/3397241/does-iphone-ipad-safari-require-accept-ranges-header-for-video 
 BotGPT:

“When dealing with video playback on iOS devices, especially when using third-party video storage servers, it's important to ensure that the server's response headers are properly configured to support smooth streaming and playback. Here are some key HTTP headers and their ranges that you should consider:

1. **Content-Type**: This header indicates the media type of the resource. For video files, common types include:
   - `video/mp4` for MP4 files
   - `video/quicktime` for MOV files
   - `video/x-ms-wmv` for WMV files
   - `video/webm` for WebM files

2. **Accept-Ranges**: This header should be set to `bytes` to indicate that the server supports range requests. This is crucial for seeking within the video.
   - Example: `Accept-Ranges: bytes`

3. **Content-Length**: This header specifies the total size of the video file in bytes. It is important for the client to know the size of the file for buffering and playback.
   - Example: `Content-Length: 12345678`

4. **Content-Range**: This header is used in response to a range request. It indicates the range of bytes being sent in the response and the total size of the file.
   - Example: `Content-Range: bytes 0-999/12345678`

5. **Cache-Control**: This header can be used to control caching behavior. For video content, you might want to set it to prevent caching or allow it based on your needs.
   - Example: `Cache-Control: no-cache` or `Cache-Control: public, max-age=3600`

6. **Expires**: This header can be used to specify when the content should be considered stale. It can be set to a future date to allow caching.
   - Example: `Expires: Wed, 21 Oct 2025 07:28:00 GMT`

7. **Cross-Origin Resource Sharing (CORS)**: If your video is hosted on a different domain, you may need to set CORS headers to allow access from your iOS app.
   - Example: `Access-Control-Allow-Origin: *`

8. **Content-Disposition**: This header can be used to suggest how the content should be handled (inline or as an attachment).
   - Example: `Content-Disposition: inline; filename="video.mp4"`

### Example of a Response Header for Video Playback

Here’s an example of what the response headers might look like for a video file:

```
HTTP/1.1 206 Partial Content
Content-Type: video/mp4
Accept-Ranges: bytes
Content-Range: bytes 0-999/12345678
Content-Length: 1000
Cache-Control: no-cache
Expires: Wed, 21 Oct 2025 07:28:00 GMT
Access-Control-Allow-Origin: *
```

### Summary

To ensure optimal video playback on iOS devices from a third-party video storage server, make sure to implement the above headers correctly. This will help facilitate smooth streaming, seeking, and overall better user experience.” 
 Partial content goes beyond headers. It requires additional logic to handle the correct ranges, HTTP status codes, and more. The `http.ServeContent` function took care of all this for you. No worries about being "bold" here. I’d much rather have range requests explicitly specified in the Blossom specs (it’s a crucial feature for a media server anyway) than deal with more half-baked, hardcoded headers scattered everywhere.

We already have too many incorrect or overly simplified assumptions about how HTTP works baked into most Nostr libraries, clients, and relays. Having something in the standarda is actually the right approach if we want Blossom to succeed. 
 Github issue for discussing it further https://github.com/hzrd149/blossom/issues/37 
 These are both pretty important for mobile, since sometimes we refuse to download things that are too big in low data mode, and ranges are nice for incremental downloads. Could mention it as a “SHOULD”