F1TV backend changes breaks video playback
NadimAsad opened this issue · 18 comments
Detailed in robvdpol/RaceControl#210. Same issue also affects F1-Web-Viewer.
Thanks for bringing this to my attention! I'll get on it!
Thank you for posting this - today was the day I decided to spin this up locally, and thought I had missed something!
F1TV looks to have reverted back the changes for RaceControl based user-agents. Information regarding this can be found at robvdpol/RaceControl#210 (comment).
With the recent change to requiring the playToken
cookie on video playback, there is some good news and some bad news. The good news is that this can be implemented very easily for self hosted users or users using the electron application. However, the bad news is that the CORS proxy I'm using strips all cookies from requests.
Unfortunately, this means that the live website will no longer work. I'll try to see if there is some way I can revive it, but I'm afraid the only solution may be to host a CORS proxy myself. Which, unfortunately, I'm not able to do at this time.
If you guys have any ideas on this, feel free to let me know!
QUICK UPDATE
I just pushed a small update to the master
(development) branch which adds support for playToken
cookie authentication. This should fix the issues reported in issue #55. However, this will only work for those of you self hosting the project or those running the Electron app. Unfortunately, these changes will not effect the live website.
Tomorrow, I'll do some thorough testing just to double check everything and then I'll deploy it to the production branch and release the update for Docker and the Electron app.
As far as the live website goes, I have no ETA on when that will be fixed. As I said earlier, the future is unfortunately undetermined as of right now
EDIT: I did a little bit of real world testing and it seems there are a few issues with my current implementation that I didn't see in my test environment. I'll be addressing those tomorrow
Just released a fix for everything except for the live website. You should be seeing the updated version show up on Docker Hub and on the GitHub releases tab shortly
EDIT: Desktop application is now released for Windows, MacOS, and Linux. It can be downloaded here
EDIT EDIT: Had a few issues with the CI. I'll manually make a build and release it today. Sorry for the wait!
Latest build as docker image here: sbkg0002/f1-web-viewer:1.17.13
Thanks for posting this in the meantime! CircleCI recently added a build limit which, unfortunately, is shorter than the multiarch build time. I thought I would be able to fix it fairly quickly, however, it's taking longer than expected.
Long story short, I'll do a manual build and release later today
Update! I had some issues building the arm64 and armv7 images manually so I only pushed the regular amd64 image for now. I'll update this comment when I get it fixed and push it out
EDIT: I was able to push armv7 successfully. Just need to do arm64 now
EDIT EDIT: and all images have been successfully pushed
Made a public version (which is basically a reverse proxy which changes the playToken cookie), and configured cloudflare to cache all ts/aac files, which might be able to reduce bandwidth usage.
Unsure if the cache thing works with live though, might need some more page rules being added
Test Link: https://live.sox.pm/
Nice! Great idea to make use of CloudFlare for caching. I'd be curious to know how you're handling everything in the backend and how you're going about hosting it. I'd love to work with you on merging your changes and coming up with a sustainable solution for this
the reverse proxy is just a tiny go script in about 40 lines, and it's not designed to handle huge amount of traffic. a tiny bit of lagging can be observed, so it's only a test at its current form, and if it works well i may carry out some improvements :D
package main
import(
"log"
"strings"
"net/url"
"net/http"
"net/http/httputil"
"github.com/gorilla/mux"
)
func main() {
handler := func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
remote, _ := url.Parse(vars["url"])
r.URL.Scheme = remote.Scheme
r.URL.Path = remote.Path
r.Host = remote.Host
remote.Path = ""
proxy := httputil.NewSingleHostReverseProxy(remote)
proxy.ModifyResponse = func(resp *http.Response) error {
if setCookie := resp.Header.Get("Set-Cookie"); setCookie != "" {
setCookie = strings.ReplaceAll(setCookie, "Path=/", "Path=/proxy/" + remote.String() + "/")
resp.Header.Set("Set-Cookie", setCookie)
}
return nil
}
proxy.ServeHTTP(w, r)
}
staticRemote, _ := url.Parse("https://f1vp.netlify.app/")
staticProxy := httputil.NewSingleHostReverseProxy(staticRemote)
staticHandler := func(w http.ResponseWriter, r *http.Request) {
r.Host = staticRemote.Host
staticProxy.ServeHTTP(w, r)
}
r := mux.NewRouter()
r.HandleFunc("/proxy/{url:https?://.*}", handler)
r.PathPrefix("/").HandlerFunc(staticHandler)
r.SkipClean(true)
http.Handle("/", r)
http.ListenAndServe(":80", r)
}
Here's the code, not well-tested but it just works for me
the reverse proxy is just a tiny go script in about 40 lines, and it's not designed to handle huge amount of traffic. a tiny bit of lagging can be observed, so it's only a test at its current form, and if it works well i may carry out some improvements :D
Ah, gotcha. I've been debating self hosting a public proxy for this since I have the infrastructure to do so, but I've been worried about bandwidth. Using Cloudflare as a CDN though should go a long way.
Thanks for posting your code by the way! I was curious to see how you went about it compared my solution. I'll probably end up creating a spin off microservice for this and then just host that. We'll see
the reverse proxy is just a tiny go script in about 40 lines, and it's not designed to handle huge amount of traffic. a tiny bit of lagging can be observed, so it's only a test at its current form, and if it works well i may carry out some improvements :D
Ah, gotcha. I've been debating self hosting a public proxy for this since I have the infrastructure to do so, but I've been worried about bandwidth. Using Cloudflare as a CDN though should go a long way.
Thanks for posting your code by the way! I was curious to see how you went about it compared my solution. I'll probably end up creating a spin off microservice for this and then just host that. We'll see
I also built a Python + Flask backend at deta.sh to do the reverse-proxy stuffs at https://tv.ieb.systems , which might be (more?) reliable than the previous one
EDIT seems deta.sh has a 5.5 MB payload size limit (aws lambda) which might be a problem for 1080p streams, I have hijacked the response to not include 1080p stream here
the flask reverse proxy: https://gist.github.com/iebb/c6fd779f206773e8b089790b4cf075a6
Mine hasn't worked at all this season thus far, but up to now I haven't had any time to do anything about it. I've read most of the stuff above, but it is pretty much literally over my head as far as how to implement the fix. Whereas when I first tried to use this during preseason and it would allow me to log in (but when choosing cameras to use, i would see an 'X' (and it would say something below that at this point escapes me), as of today I can't even log in when trying to use it.
Is there any sort of 'how to' I can follow to fix mine? I know my subscription is working since I can log into F1TV and watch that way, but despite the improvements there, you all are still way ahead of the curve they set so I'd like to stay watching the races as I have the last year or so since I read and applied the app. So any help or suggestions would be appreciated.
Thanks in advance (for help/suggestions as well as making this available for the rest of us to use and enjoy).
@xAndrettix For now the easiest way to get something working is by using iebb's Self Hosted version. Just download a release and run it. https://github.com/iebb/F1WebViewer-SelfHosted/releases