视频分享应用48小时
上星期,我被邀请到 专用黑客hon为音乐家搭建应用应用团队我分配 任务搭建视频上传网站BOZ是一种音乐风格 原创新奥尔良程序调用bunceDotCom.com 并有计划大自由度皇后喷雾推广我知道组织者能实现事端 所以我跳跃机
球队上是我 布拉德休伯和多伦谢尔曼约48小时实现周一晚我出现 团队开工后 来想出计划 和如何帮助铁路公司有一个基本后端第二天我本想早点来 JavaScript和Recact前端工作
现在,人们可能知道 我宁愿ClojureScript自己比JaavaScript但我也是实用论者然然我本可以在ClojureScript工作,接通应用更新取决于我的进度币游平台网页版官方使用纯JaavaScript会提供更多灵活性,特别是在资源紧缺而未来未知的地方。
第二天早上,我开始搭建变序前端,以便测试它我用过create-react-app开始配有dev搭建系统,以便自动加载代码保存我是快速反馈大粉丝保存重载工作流不如ClojureScript工作流好,但足以满足像这个小项目ClojureScript中,新代码重加载时不丢失当前状态,因此点击少得多
一开始我的主要焦点是获取视频上传工作我知道这将是最大挑战从多设备上传文件并贴入a加法应用没有它就一文不值如果人们无法上传视频 网站主概念将不存在多龙大帮助 提供文档时我需要云形提供多种不同解决方案, 包括贴贴视频或浏览部件面向48小时项目,我选择部件我不可能相信48小时内能做得更好
正常工作时 花一天研究你最佳选择 完全值得投资Chackathon不理智快速寻找可接受并发扬光大发现三种不同的部件 看起来像它们可能工作 我们使用案例和栈归根结底 最先成功者超易实现仅在HTML中包括此内容
Here’s what it looks like:
And on mobile:
That will fetch a script with everything you need. Here is how I show the widget.
window.cloudinary.openUploadWidget({ cloud_name: CLOUD_NAME, upload_preset: 'default', }, (err, result) => { });
You get the Cloud Name from your Cloudinary account. I had to create a preset in the dashboard that allowed for unsigned uploads so anyone could upload a video from their phone using only the frontend.
To display the videos, I tried cloudinary-react and it worked very easily.
The component worked right out of the box, but we did have to fix some issues. It worked fine on desktop, but on my iPhone, the poster wasn't showing up. That's why I added the poster attribute manually in that code snippet. Problem solved. Luckily, Cloudinary is smart. If you ask for the .jpg file, it will give it to you and generate it if it needs to. If you ask for the .png, it does the same. It works better than you expect, because most services don't do this kind of transformation on the fly. But Cloudinary does, and it works the way you want it to work.
Notice that I set up a React ref for the video. I wanted to be able to stop and start the video in my scripts, so I needed a direct reference to the video element. The react-cloudinary components render out to regular HTML video elements.
How do I know?
I read the code. Yep, it's readable code. And when you're on the super tight deadline of a hackathon, you don't have time to read inefficient English text documentation. You go straight to the render() method. Code doesn't lie.
Another thing I learned from the code was that if the react-cloudinary components don’t understand a prop, they just pass them right down into the video element. So I could put onPlay, onEnded, and onPause callbacks right in there. A really nice touch.
Then I hit a snag.
The Cloudinary upload widget lets you upload videos and images. But there's no way to limit it to only videos. Well, not that I could find. If you said "only .mp4 files", it still lets you take a picture and try to upload it. Then it fails and you lose your picture. For our use case, that is a terrible user experience. People are having fun at a party, they take a really awesome picture they want to share with their friends, but instead the app drops the photo on the floor. The uploader works fine, but our app was never meant to host images. I could write a custom uploader, but I didn’t want to spend the time.
So what did I do?
I made an executive decision: We would support photos. This required a small backend change that I could not make, since I am clueless when it comes to Rails and Ruby. We needed to record whether it was an image or a video along with the media id. I made the changes to the frontend that I could, and allowed images to be displayed, and recorded an issue for the necessary backend changes in the backlog.
Here’s how you display an image from Cloudinary:
Super easy. The only thing I wish for here is that you could tell whether it was an image or a video from the id. I could query the API, but we wanted to minimize the number of requests to keep latency low. Plus, on mobile, each HTTP request is just another chance to fail.
So, by lunchtime, what did we have?
We could list videos (with inline playing and nice thumbnails) and upload new videos. We had a login system so we could identify users. Was it a nice app yet? No. Was it completely easy and straightforward? No, I can't say it was. But it was mostly forward progress. I mean, that was basically four hours of work to get video uploading with transcoding to multiple formats. Oh, and remember, it worked on desktop, iPhone, and Android with the same code. Not bad. And by “not bad”, I mean wow! A video app in a morning! I did not imagine this was possible before I met Cloudinary.
After lunch we started to put it on the open internet so we could have some kind of deployment pipeline. Until then, it was just me serving it from my laptop. We had some snags with that, too. For example, Heroku decided to upgrade its DNS to support SSL which did not allow us to add custom domains for a few hours. But in the end, we had everything hosted on Heroku.
At this point, it was 6 p.m. I had been adding a bunch of stuff to the backend backlog, since as I said, I don't know Rails. Lucky for us, Brad Huber, my teammate, knew plenty. I had to run but I would be back. I was hopeful to have all of my backend requests finished when I returned.
When I came back, it was on again. It was after 10 p.m. Some of my changes had been implemented, but not all. One of the things I requested was to be able to store arbitrary JSON data with users and with videos. In a hackathon, you just don't have time to mess around with designing a data model, and you certainly want to remove any reason to coordinate with the backend team. They have better things to do than add this field and that field to the model. It's much better to just let the frontend store whatever they want.
The break from coding had given me a new perspective on the app. I had been thinking about it mostly as a desktop web app. And our backend reflected that. It required users to register and login to upload a video. But after taking a break and seeing some issues logging in on some phones, I decided we needed to focus 100 percent on the main use case: the app would be demoed at a party the next night. People would want to pull out their phones, film some badass dancing, and upload it to share. They don't care about logging in. If they had to do that, they wouldn't have as much fun.
So how did we solve it?
We got rid of the login. You go to BounceDotCom.com, you click a button, record some video, and upload it. It shows up. You rock. That night, we recruited a couple of designers to draw some designs and implement it.
And then we passed the point of no return.
I hadn't eaten dinner. There was some food left I could scavenge from. And then Doron offered me a bubble tea. Great, I thought. It looked milky and those tapioca balls could sustain me. I started drinking it. And then I realized, too late, that it was coffee. I'm super sensitive to caffeine, especially that late at night. I doubted I would sleep that night.
And I didn't.
I stayed up all night coding on this app. There were several things I needed to do. We wanted a strong viral component, so I added Facebook sharing. To do that you need some Open Graph metadata in your HTML and some JavaScript for Like buttons. I hacked on that through the night. But Cloudinary made this really easy. Here's a snippet from the HTML template:
{{#video}} {{/video}} That {{&image}} and {{&video}} get replaced on the backend by this: if(pid && type === 'image') { image = `https://res.www.agrosoland.com/${CLOUD_NAME}/image/upload/${pid}.jpg`; } if(pid && type === 'video') { image = `https://res.www.agrosoland.com/${CLOUD_NAME}/video/upload/${pid}.jpg`; video = `https://res.www.agrosoland.com/${CLOUD_NAME}/video/upload/${pid}.mp4`; }
That is, we can generate image URLs and video URLs pretty easily for Facebook to use. Liking and sharing work pretty well. And it was thanks to Cloudinary's ease of use.
And then there was a surprise:
Travis Laurendine, the organizer, showed me that if you send a link over iMessage, it embedded the video right in there. Hello!! That was totally unexpected.
I crashed pretty hard around 10 a.m. I took a four-hour nap. When I woke up, I loaded the app to find it purple and beautiful, thanks to those designers. I fixed some CSS and added a play button. Everything was coming together. I worked on it a little that afternoon, but nothing so intense as before.
So what became of our demo?
In the end, the demo party never happened. It rained pretty hard and Jazz Fest kind of took over everything. But the app is there, still running and waiting.
With the main functionality of the app working, what’s next?
We have plans to migrate away from Heroku and onto a serverless cloud service. We don't really do much on the backend that couldn't be done cheaper and better on Google Cloud Platform or AWS. Using Lambda and Cloudinary, we basically have no overhead.
Low overhead is important for an app like this: if it doesn't take off, it costs next to nothing. But if it does, it will scale effortlessly. The other thing we might do is rewrite the uploading code. We're using the Cloudinary widget and we might want more control of the user experience. We'll want something customized where you click a button and it opens the camera, ready to record. However, I think that it will be complicated to get something working so well on all devices. It will have to wait. The Cloudinary widget works very well. It just does more than we need and those extra features could get confusing at a party.
I have to emphasize again that no one on the team had used Cloudinary before, except Doron, our contact at Cloudinary. Any app has engineering decisions that need to be made. Cloudinary’s employees, documentation, and code helped us stay on track. I am still surprised by how much we figured out and built in less than a day. The tools they give you, including the libraries, dashboard, and APIs, are where it really shines.
I look forward to hacking on this app in the future. And I’ll be dreaming up new ways to put Cloudinary to use.
Eric Normand is a long time functional programmer excited to see it entering the mainstream. He loves teaching and cooking. You can learn Functional Programming and Clojure from him at PurelyFunctional.tv and get inspired by The PurelyFunctional.tv Newsletter. If you visit him in New Orleans, you can meet his wife and daughter. He'll even make you some gumbo if you tell him you're coming. |