Release 0.2 2018

For my second open source release, I had a lot planned weeks in advance. However due to the nature of open source sometimes things don’t go as planned and you have to improvise. In my case, I had to find a completely new project to escape the plague of my pull requests getting closed consistently and as noted in my previous post I ended up finding a pretty good project called Chart.js which is a JavaScript library to generate detailed charts. The bug I picked up for the project was to fix the array tick label alignment. Example:

Problem:

p1.JPG

Solution:

ch2

As shown above, the main problem here is that the initial label in the array is centered however each consecutive label in the array is being printed below it and not being centered. To fix this initially I wrote:

context.translate(0, -tickFont.size * (label.length / 2));

which moves the labels up by the font size multiplied by the length of the array divided by two. This equation essentially finds the spacing between one label and the other and moves it up by that amount of space. For example to move “Row two” to the position of “Row one” it would need to be translated by negative eighteen. This was what I put up in my first pull request and as a result I got some good feedback.

p2.JPG

p3.JPG

It turns out my initial approach to fixing this issue had some flaws and thankfully I got some great guidance instead of having my pull request closed instantly like when I was working on other projects. Pettiness aside the problem with the code was that it was  slower to translate the label via the context than to move them using “y”. “y” in the code sets the initial printing position of the label so offsetting “y” would create an easier solution than translating the labels after the fact which is something I hadn’t thought of. Also if the graph was in vertical mode my code wouldn’t account for it and it ended up moving the labels into the bars.

Taking all the feedback into consideration I began writing code to update the pull request with the necessary changes.

Result:

p4

This code also had some minor problems like using ternary operator instead of an if statement to check if the graph is horizontal and using predefined variables in the for loop. I began working with Simon Brunel who is one of the lead developers for the project so we could both find the right equation. It was apparent to me that we both different ideas on how to write the equation and some which were both incorrect.

p5

p6.JPG

In the pictures above Simons comment is the result of my equation and my comment is the result when using his equation. We were both slightly off but I’m glad I had someone to help me with the process. From this point, it seemed like we were both awfully close and were missing the small thing that would make the equation work for all cases. Shortly after that comment, I decided to try to divide the whole equation by 1.2 which was the hardcoded line space value in the project. I thought this worked, however, Simon found the real reason the equation wasn’t working.p7

Simons new equation ended up working thankfully and I put up an updated PR that got approved and merged shortly after. Although it wasn’t me who figured out the correct equation, in the end, I still felt like a fundamental part of the development process. Also being new to the project I didn’t know the key terms and variables that would influence the creation of the correct equation. Overall I really enjoyed working on this project and hope to tackle other bugs in the future I loved all the feedback and help which will keep me coming back for more bugs!

Pull requests that were wanted features but were rejected for this release:

Adds Custom Error Message

Adds Next and Previous Song Buttons

Advertisements

Finding Exciting New Open Source Projects February 2018

Since my ideas of Open Source didn’t align with the previous project I was coding for I decided to begin yet another search for an exciting new project to join. I already had a fair bit of knowledge about HTML5 canvas from the previous project and decided to find something new where I could transfer my existing knowledge. Thankfully GitHub has an explore option where you can search for a specific project depending on language, category, etc. It didn’t take me long to come across a project called Chart.js which can generate a graphical chart using the HTML5 canvas element and JavaScript. chartjs-tutsplusThe beauty of Chart.js is it can be used to generate charts and graphs dynamically meaning if you have a database full of statistics or other meaningful data you can query that table data to populate and generate multiple charts at once which could prove to be very useful instead of hard coding all the data into a graph. The project is also very popular because of this making the implementation of graphs into a project very simple and intuitive.

Example:

ch1

ch2.JPG

To get involved with the project I took a look at the issue list and scanned for some good starter bugs to give me a good intro on how the code and application works. I came across a bug that had to do with label array alignment. The main issue here was that if there was an array of labels the first one would center with the bar, however, the preceding labels in the array would just be printed beneath it and wouldn’t be centered with bar. There was a fair amount of information provided about the issue and even a JSFiddle demonstrating it. One of the maintainers also commented where the fix would potentially be in the code which gave me an excellent idea of where to start with the bug. Thankfully with all the information provided was able to code and test for fixes within an hour as for other projects it often takes a couple hours of code reading to figure out where everything is. I hope to have this bug fixed and merged in the near future and will write a separate post outlining the fix and process.

Overall I’m very excited to get my first pull request in for Chart.js and will be picking for interesting bugs in the near future.

 

Open Source Release 0.1 2018

I began this year with the ambition to contribute to new and exciting projects and work on bugs and features outside of my comfort zone. As mentioned in my previous blog post I decided to work on a project called JSPaint which in summary is an application aiming to recreate the original MSPaint completely in JavaScript with additional features and functionality.

Learning the inner workings of JSPaint wasn’t as hard as I expected and I enjoyed seeing all the uses HTML canvas can be used for. The whole concept of JSPaint is essentially built around a singular tag, “canvas”, which allows the users to draw images and shapes on a plain/canvas. Canvas can be manipulated in many ways to retrieve the developers desired effect which is basically what happens in JSPaint which could be labeled as a highly manipulated and modified HTML canvas. Having the project operate around this tag made it easy to develop for because canvas is widely documented online which meant finding information and figuring out how to add a certain feature was a lot easier than code written primarily for a specific project. For example, a project I worked on called APlayer had code written proprietarily for itself meaning there is no looking online to see information regarding the project itself and it had to be deconstructed by the developer. Overall it was nice working with a project that had pages and pages of documentation regarding its inner workings easily accessible.

The first “real” issue I did for JSPaint besides a small CSS fix was adding the ability to copy a selection when holding the control key. A user pointed out that in the original MSPaint when you select a portion of the canvas and click while holding control it essentially acts a quick way of enacting ctrl+v or right click and paste. I thought this was a great feature to add as well and began working on a way to implement it to the project. Originally when I took my first go at figuring out how to implement it I ended up writing way too much code than I thought I should and ended up in a bit of a rut. It was almost as if I got lost in my code and couldn’t figure out the actual solution to the problem because I had written all this code that ended up slowing me down. I took a small break and realized that I only had to add one “else if” to the canvas pointer down listener that would check for control being pressed and if so draw the image that was in the selection box. r1.JPGAfter all my hours of coding in circles, the final fix ended up being only being three lines of code which made it really easy for a pull request.

After having my first feature merged with the JSPaint master I wanted to work on more features listed under issues because it was exciting to me to add something new to a project instead of fixing a bug. So thus I took up another feature which was to implement a contiguous global fill feature. Aside from the fancy words this essentially means implementing a feature that allows the user to change a single color globally on the entire canvas. r6For example, if I have two red circles and I use the fill tool while holding shift it had to change both red circles to blue or the desired color. This feature wasn’t in the original MSPaint which gave me more drive and excitement to work on it. I asked if I could implement it on the issue and was given the all-clear. r8This feature took a lot longer than the previous one and I had to really do my research on the inner workings of HTML canvas to figure out if it could even support a feature like this. The first finding I found which was really important which was that HTML canvas can’t natively record history which means whatever is added to the canvas is considered its only state. This was a problem because my original method for changing the color globally was to capture each object on the canvas and edit them in a loop to all be the same color depending on what the user chose. This didn’t end up working even with the fact that JSPaint has a history feature built-in in the form of the undo feature. The reason this method didn’t work was the undo methods functionality would work by saving an array of canvas objects meaning it essentially takes a snapshot of the entire canvas at that time and not the object. It would be extremely inefficient to scan every canvas object for a color than just scanning the current canvas. What I ended up doing was scanning the current canvas pixels for the color that was to be changed and then editing the pixels individually to the new color. With a couple hours of work and tweaking this ended up working and I submitted a pull request showing off the feature. r2To my surprise the next morning I got a considerate amount of feedback and saw that the PR was closed instantly. I was kind of surprised and let down because usually when a maintainer requests changes you get some time to implement them and fix you PR. This wasn’t the case and couldn’t help to but feel disappointed that the maintainer decided to take bits and pieces of my code and implement it in a way that he saw fit which is entirely fine however not really the main focus with maintaining an open source project.r9 I believe a good open source project allows contributors to correct their PR’s so they one, learn how to right non-buggy code, and two so they keep coming back to write more code for your project. This ended up happening to another one of PR’s which added the feature to move a selection with the arrow keys which is in the current version of MSPaint. r5The reason is mainly that the maintainer knows exactly where and how he wants it written and figures it is better if he implements it himself.

Overall my time working on JSPaint has been great however I most likely won’t be working on it again in the future and will begin my search for a new exciting open source project!

Looking For New Exciting Open Source Projects

Beginning this year I wanted to start working on a new ambitious Open Source project. I thought it’d be easy given the number of open source projects across the web ranging in the hundreds of thousands. However, with the colossal amount of projects, I found it fairly difficult to find one I wanted to wholeheartedly contribute to. With contributing to an open source project it’s not as easy as picking something you think is cool and working on a bug, there are a number of factors that contribute to whether that project is viable and logical to work on. In my “selection” process I considered the following factors: “is the project active?”, “Can I work on the project with my current skillset and if not can I learn it?”, “Are the maintainers actively merging and tending to issues and pull requests”, and “do I like the project?” I used these questions to pick the open source project I wanted to work on.

I began my search by looking at music projects across GitHub because I love music and instruments and have been playing piano and guitar for many years. Previously I worked on APlayer by MoePlayer and that was great however I wanted to work on a new project and expand my portfolio. I came across a lot of interesting projects, for example, Mopidy which is an extensible music server that plays music locally, Spotify, Soundcloud, and many more. download.pngI liked the purpose of this project, however, I was worried about the extent of work I could do on the project aside from small bug fixes since the project fulfills a small array of purposes being a music server only. After careful consideration, I decided not to work on Mopidy and continued my search for other viable projects. I went through project after project checking if they aligned with my “viable project” criteria and narrowed it down to a project called Google Play Music Desktop Unofficial (GPMD). GPMD is an unofficial (not from Google) desktop application that allows the user to use Google Play Music as a desktop application. The project looked really interesting and I saw some issues I thought I could tackle with ease. One of which was the adding a message to the user in the event that the GPMD is launched without an active internet connection. I forked and cloned the project and begun analyzing its source code. GPMLogo.pngAfter an hour or two I beginning to think that this project was somewhat beyond my scope and I didn’t have the required skillset to correctly contribute to project. I tried for another hour or so and kind of placed the project on the backburner to search for different projects however this time branching outside of the music category.

As the hours went by of passively analyzing different projects I was worried that I wouldn’t be able to find the right project for me and ended up having my doubts. I found myself staring at the GitHub homepage and noticed a project on trending called JSPaint. mspaint.jpgjspaint.jpg

I took a look at it not really thinking I’d ever work on it and scanned through the issues. I noticed one called “zoom is blurry on Firefox” and thought it should be a simple fix since zoom worked perfectly fine on other browsers and that it could possibly be firefox having different syntax. This was somewhat confirmed by the owner of the project when he mentioned new syntax regarding image rendering. I forked and cloned the project and begun working on the issue. To my surprise, it only took a small addition to the CSS to fix the issue and I have it Pull Request form in under an hour.

It was funny to me that previously I set so many criteria to find a project to work on and ended working on a random project I came across on GitHub trending. I hope to continue working on this project and have really enjoyed working on it so far.

 

Release 0.2

After completing release 0.1 and finishing the Hacktoberfest challenge I have found a new passion for collaboration and open source development. Once I noticed that inputting “g” on my Chrome address bar automatically fills in GitHub.com I knew I that even my computer was taking notice of my new search trends towards open source development. moe 2I wanted this release to be exponentially bigger than the first now that I have learned so much about Git, collaboration, project discovery, etc. I also wanted to test myself and see how far I could go on something that’s not just a bug, however, collaborating on a project and adding something new the user wants. In light of my new set goal for this release, I began my extensive search across GitHub for projects that interested me. I know if I am interested in the project I will be more inclined to go the extra mile and as well as appease my interests so it turns into more fun than work. I love all aspects of music from playing piano and guitar to listening to music on Spotify for hours, so I wanted to see if I could find some type of music project to work on since GitHub is huge and is bound to have something.

The search wasn’t as easy as I thought and I found a lot of half-baked or not really my kind of project to dive in until I came across a project called APlayer. When I initially came across this project it didn’t look relatively active with the latest pull request dating back to sometime in April 2017 and some of the issues being a fairly old. I liked the look of the project and thought I could take on some of the issues so I decided to reach out to the lead developer (DIYgod) of the project and ask him if it was still active and if new contributors are welcome to fix some issues. I got the following email around the next day: moe 1

I was really excited about the opportunity to join the MoePlayer organization on GitHub as well as getting the good news that I could work on the project I wanted to. Shortly after I took a look at the APlayer issue list and took on a simple one to start (link) which was a bug where a hyphen would be present even if the author field is null. The fix for this was fairly simple and I just had to add a ternary operator in the JavaScript that checks if the author is null and if it is then the hyphen would not be printed. Initially, it wasn’t simple and I had to do around an hour of code reading to understand the project and how it functions however after that it was smooth sailing. Once I got the PR (pull request) in for the issue DIYgod accepted and merged it fairly quickly and I somewhat used that first PR as a “proving myself” that I could be apart of the MoePlayer organization.

My second bug wasn’t a bug at all because I decided to take on a bigger issue which was to add a feature to remove songs from a playlist which functionality was not in the APlayer project. I began work on a fix which I showed off in about a day and got responses that wanted me to adapt it as an API instead of it being in the UI which it was initially (link). I went back to work on it for a few days and opened a PR with what I thought was the full fix. To my surprise, I had some bugs and quite a bit of code suggestions too from a reviewer that I had to change. I’m really grateful that my code got reviewed so intricately because it taught me a lot about modern JavaScript as well as how a feature is developed. learn-javascriptThis feature had to be perfect and error free because the product “APlayer” is going to be used on hundreds of sites around the world. That’s one thing that somehow escaped me in the first development phase of the feature and I’m not sure why. Small things like “if the player is paused and you delete that song the player should remain paused” which was something my code didn’t account for and I had to adjust my code to check the players play state, pause state, as well as the current song being played.

I’ll call this the second stage of my development process with the remove song feature because this where things started to heat up and I had to think of the perfect logic to support this use case and be 100% error free. I also wanted my second PR to show major leaps in improvement so that I wouldn’t bother the lead developer as much by consistently iterating on my older code. I had to monitor things like the play index of the song so I could check if the current song is being deleted and apply the appropriate logic for that situation as well as delete the song from two parallel arrays audio and music one which holds the songs credentials like author, source, and name and the other which handles the audio playback aspects for the song. Applying all the appropriate logic took a long time and there were moments where I was convinced that APlayer wasn’t designed for a remove song feature however after moments of taking a break I felt compelled to take another look at the code and try to figure out how to create this feature. I even had my friends test the feature to make sure there wasn’t a bug I missed to which one was found and I had to fix it shortly after. After about a couple days in and out of development I came up with this:

/**
* Remove song from playlist
*/
removeSong(indexOfSong) {
if (this.option.music[indexOfSong] != null) { // Check if song exists
const list = this.element.getElementsByClassName('aplayer-list')[0];
var oList = list.getElementsByTagName('ol')[0];
var liList = oList.getElementsByTagName('li');
if (this.option.music[indexOfSong + 1] != null || this.option.music[indexOfSong - 1] != null) {
if (indexOfSong == this.playIndex) {
if (this.option.music[indexOfSong + 1] != null) { // Play next song if it exists.
this.setMusic(indexOfSong + 1);
this.playIndex = this
.playIndex – 1; // Adjust play index for removed song


}
else if (this.option.music[indexOfSong + 1] == null) { // Play previous song if it exists.
this.setMusic(indexOfSong - 1);
}
}
else {
if (indexOfSong < this.playIndex) {
this.playIndex = this.playIndex - 1;
}
}
if (liList[indexOfSong
 + 1] == null) {


var targetSong = liList[indexOfSong - 1];
targetSong.getElementsByClassName('aplayer-list-index')[0].textContent = indexOfSong;
}
else {
for (let i = 1; i < liList.length; i++) {
if (liList[indexOfSong + i] != null) {
var targetSong = liList[indexOfSong + i];
targetSong.getElementsByClassName('aplayer-list-index')[0].textContent = indexOfSong + i;
}
}
}
this.option.music.splice(indexOfSong, 1); // Delete song from music array
this.audios.spli
ce(indexOfSong, 1); // Delete song from audios array


liList[indexOfSong].remove();
if (this.option.music[0] != null && this.option.music[1] == null) {
this.multiple = false;
this.element.classList.remove('aplayer-withlist');
}
}
var listHeight = parseInt(list.style.height, 10);
list.style.height = (listHeight - 33) + "px";
}
else {
console.error("ERROR: 
Song does not exist”);


}
}

View better formatted code here: removeSong(indexOfSong)

Example: moe 3.gif

I am really proud of this code and though it’s not the biggest piece of code it took a lot of thinking and testing to get to that point. A couple of days after and some minor changes requested by the lead developer I finally got my feature merged with the master branch which was a huge accomplishment for me.

After completing this feature I had a sense of emptiness that I wasn’t used too, for the last couple weeks I had been consistently working with APlayer and this feature that it was weird that it was all over. During development, I did notice an issue with APlayer which was if you click addMusic(…) on the demo page and then collapse the playlist into a single song and then click addMusic(…) again you wouldn’t be able to open the player into playlist mode anymore (link). So I decided to open up my own issue on the APlayer GitHub page and fix it myself within a couple of hours. I got some feedback and minor requested changes to the code and got it merged with the master branch which went a whole lot faster than developing the remove song feature.

Overall I feel this release was everything I wanted it to be. I got to work on a project that aligned with my musical interests, develop a completely new feature, and fix a few bugs some of which that I discovered myself during development. I can’t wait to see what I work on next in the new year!

Async Image Load Test and Code Reading

Even after doing years of coding a software development I always find there are infinite things to learn when it comes to computers and technology. I wouldn’t have thought that a simple image load test would test my understanding of JavaScript as a programmer. This was basically the original testing code given
var img = document.querySelector('#image-1234');
img.onload = function loaded() {
};
img.src = "http://some.url.com/image";
img.src = "http://some.url.com/image";

Which to me initially looked like a perfectly fine piece of code that would run fairly straight forward. The code is meant to set source of an image and then later in the code set the source of the image again. Sounds easy however after a small modification to see if the code was setting the image source twice I noticed that it wasn’t happening at all.

Original test code modified:


var img = document.querySelector('#doggo');
var onloadUpdate = document.querySelector('#update');var onloadCount = 0;
img.onload = function loaded() {
console.info("FIRE THE ONLOAD!");
onloadCount = onloadCount +1;
console.info(onloadCount);
onloadUpdate.innerHTML = onloadCount;
if(onloadCount == 1) {
document.body.style.backgroundImage = "url('error.jpg')";
}
else if(onloadCount == 2) {
document.body.style.backgroundImage = "url('success.jpg')";}
};
img.src = "doggo.jpg";
img.src = "doggo.jpg";

The code above counts how many times the onload event runs and displays it on the screen as well as changes the background depending on if the image loaded once or twice giving an error or success type background. To my dismay the onload event was only running once which left me a little confused. This happened across all browsers I tested which were Google Chrome, Internet Explorer, Edge, and Mozille Firefox. Luckily Professor David Humphrey offered me some assistance, see below:

lab11 1

The problem I was having was a synchronization issue, since I was setting the source twice one after another the first setting of the source wouldn’t have time to load and it would skip to the second and thus enter the onload function only once. The key was to make sure the initial image was loaded and then load the image again which then made onload fire twice as desired.

Modified Test Code: 

var img = document.querySelector('#doggo');
var onloadUpdate = document.querySelector('#update');
var onloadCount = 0;
img.onload = function loaded() {
console.info("FIRE THE ONLOAD!");
onloadCount = onloadCount +1;
console.info(onloadCount);
onloadUpdate.innerHTML = onloadCount;
if(onloadCount == 1) {
document.body.style.backgroundImage = "url('error.jpg')";
img.src = "doggo.jpg";
}
else if(onloadCount == 2) {
document.body.style.backgroundImage = "url('success.jpg')";
}
};
img.src = "doggo.jpg";

In this modified code the source is only set again if the first source has been loaded already thus eliminating the synchronization issue. It’s interesting how JavaScript handles image loading like this and I would of most likely run into this issue in the future if I hadn’t addressed it now. As a programmer I’m so used to reading code top down (even though I have down extensive work with Threads and AJAX) that for some reason the concept actually took me a while to understand and thankfully Professor Humphrey wasn’t hesitant to help explain something that seemed super simple.

Click to run the test for yourself!


Another goal was to find the code behind the image load capability of the browser which turned out be a bit more difficult than I initially thought. I had no idea that most browsers are actually written in C/C++ which is really interesting because it’s a language that we learned how to do a lot of logical/mathematical things with however in classes we never applied it to much outside of that. firefox logoIt would be interesting to brush up on some C++ and try to understand and improve some of the existing Open Source browsers like Mozilla Firefox and Chromium. chromium logoAnyway, during my search I went through the mass amount of source code in Chromium and Firefox, not so much to my surprise searching image in the source code gave me around 150,000+ results which made it very difficult to search through being one, not a C++ buff as well as having no previous experience navigating a browsers source code other than to build it manually. Mostly I was relying off of class names like Image.h and Image.cpp however when asking my professor if those files were the ones behind onload I quickly found out they weren’t. This wasn’t the end for my search, for being a Software Developer means having excellent Google skills so I simply googled the issue I was originally having (image source won’t load twice when called twice). I ended up coming across a bug post from 2009 in which a Chromium developer had the same issue “image onload event does not fire when loading an already loaded image” which was kind of cool to see open source bug collaboration dating back that far as well as finding somewhat what I looking for (the power of Google!). At the bottom of the post there are some links to what I’m thinking is the modified code to address the issue which in term gave me the name of the rendering engine for chromium as well as the filename for the code that handles the onload functionality. Another quick google search and I ended finding the source code for an image load which is appropriately called ImageLoader.cpp *facepalm*.

Set image code:
void ImageLoader::setImage(ImageResource* newImage)
{
setImageWithoutConsideringPendingLoadEvent(newImage);
// Only consider updating the protection ref-count of the Element immediately before returning
// from this function as doing so might result in the destruction of this ImageLoader.
updatedHasPendingEvent();
}


void ImageLoader::updatedHasPendingEvent()
{
// If an Element that does image loading is removed from the DOM the load/error event for the image is still observable.
// As long as the ImageLoader is actively loading, the Element itself needs to be ref'ed to keep it from being
// destroyed by DOM manipulation or garbage collection.
// If such an Element wishes for the load to stop when removed from the DOM it needs to stop the ImageLoader explicitly.
bool wasProtected = m_elementIsProtected;
m_elementIsProtected = m_hasPendingLoadEvent || m_hasPendingErrorEvent;
if (wasProtected == m_elementIsProtected)
return;
if (m_elementIsProtected) {
if (m_derefElementTimer.isActive())
m_derefElementTimer.stop();
else
m_keepAlive = m_element;
} else {
ASSERT(!m_derefElementTimer.isActive());
m_derefElementTimer.startOneShot(0, FROM_HERE);
}
}

Overall it was interesting to see how what originally went from testing a simple image loading example went to figuring out how browser event loading works and taking a deep dive into the source code that makes the whole system works itself. As for the future I’d like to try to do some browser coding to improve my C++ and to work in something I haven’t really thought of doing before.

Planning For Bug Release 0.2

Ever since I fixed my first bug I have become fascinated with the fact that I can jump onto to a random project and start contributing. I always had a love for music ever since I was a child and learned how to play piano, guitar, and produce music to help feed my passion. On the other end I also love computers and technology so I wanted find a middle ground where I could develop employable skills like software development as well as my hobby being music. Lab10 1To do this I searched all around GitHub for music based projects that I could possibly contribute too and fell across a project called APlayer. APlayer is an HTML5 music player programmed in JavaScript. It allows you play songs locally or across the net as well as make playlists and add cover art to songs. In my opinion it’s really cool and after spending some time working with the raw code of the project I can see it has a lot to offer.

When I first landed on the projects GitHub page I noticed most of the issues and pull requests were rather old and didn’t have a lot of activity which made me worry initially. I decided to email the author of the project and ask if it was still actively running and if I could work on it to gain experience in school. To my surprise the author “DIYgod” replied in less than a day saying that he was busy with his full-time job now to work on the project but invited me to join the organization and start contributing instead. After reading the reply I got pretty excited because I’ve always wondered how to join an organization on GitHub and if I’ll ever be invited to one. Eo6BOvqbdIIt’s nice contributing to a project however being part of the projects organization and contributing felt a lot better in my opinion. It gave me a sense of ownership for the bugs I was fixing and features I was working on even though it’s as silly as just having a little badge on your GitHub page. Never the less I hope to work on more bugs and features for APlayer and possibly branch off to other projects in the MoePlayer organization like DPlayer which is an HTML5 video player for the browser or cPlayer which is another web based media player.