I spent some time today updating the README for Youtube-Gif-Go, and writing one for youtube-gif-go-frontend. It was hard thinking about the features and description for both of these. Specifically, I’ve been thinking of them as toy projects for so long that it was hard to appreciate the work I put into this project. I had to look at the frontend for a bit to remember what I like about it. I realized today that the top few services for converting YouTube videos to GIFs don’t let you crop (mine does). This made me excited…
Until I remembered yesterday’s hack. The summary of the problem from yesterday is: a client can say “show videos in a 300 by 300 pixel square”, and YouTube will try to find a video to shove in that square. There’s no promise the source video will be that size, and in fact, it’s very unlikely it will be that size. You can ask for sizes with phrases like “medium”, and even then it’s not guaranteed.
This isn’t a problem, because you can just send the size of the player along with your crop coordinates to the backend. The backend can see the size of the video it downloads and scale the coordinates. I knew this and told myself this days ago, then forgot all about it and burned time exploring some nutso solution. So in the interest of honesty, here goes:
I spent a few hours disassembling the different SWF files that the YouTube player uses. It turns out:
- You can get the SWF that gets constructed when you embed a YouTube video
- Which in turn calls upon two SWF files
- One for failed loads
- One generic file that contains knowledge of playing YouTube videos, and all of the other fun things. For example, when you right-click a YouTube video, you’ll see an item on the menu for “Stats for Nerds”. It’s contained in the watch_as3.swf file.
I also spent a while examining the network calls that the flash player was performing on my behalf. I noticed that at some point, the get_video_info internal API seemed valuable. You can make a request with a video ID, and your player size, and receive lots of information. Strangely, the response is a massive payload of URL encoded data, containing elements that also have URL encoded data. Decoding this data provides what appears to be a list of options. I tried to determine how the player decides which option to choose, since my example video was falling past the first option. I’m not sure what I would have done with this information.
I eventually stepped away to make coffee, thought about the problem, and realized I wasted a lot of time.
Earlier in the day I switched the API so that creating a GIF provides the user with a job resource. The job can be polled until the status is ‘available’, and then the GIF resource with the same ID will load. This simplified the consumer and made me feel much better. I also looked into some tools that frontend developers commonly use to make their workflow easier. It was interesting, but I’m getting itchy to work on some non-frontend stuff, so it might have to wait for the future. Tomorrow I’m gonna fix the crop thing and look at WebSockets. If I’m still excited about the project, I’ll keep going with WebSockets. Otherwise, it’s either Clojure time or Performance Engineering of Software Systems, which looks ultra cool.