Compare commits

...

No commits in common. "625bd968a6ba8a829e5a4ed50278de75a9136153" and "944f53553267ef2096a9fae8720a4debee9ecb4c" have entirely different histories.

10 changed files with 2873 additions and 11 deletions

8
.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# ignore the compiled files
build/
# ignore node_module directory
node_modules/
# ignore SASS cache
.sass-cache/

61
.sass-lint.yml Normal file
View File

@ -0,0 +1,61 @@
# Linter Options
options:
merge-default-rules: false
formatter: checkstyle
output-file: 'build/checkstyle.xml'
files:
include: 'src/sass/**/*.s+(a|c)ss'
ignore:
- 'src/sass/vendor/**/*.*'
# Rule Configuration
rules:
extends-before-mixins: 2
extends-before-declarations: 2
placeholder-in-extend: 2
leading-zero:
- 1
-
include: true
mixins-before-declarations:
- 2
-
exclude:
- breakpoint
- mq
border-zero:
- 2
-
convention: none
no-warn: 1
no-debug: 1
no-important: 2
hex-notation:
- 1
-
style: lowercase
indentation:
- 2
-
size: 2
property-sort-order:
- 1
-
order:
- display
- float
- width
- height
- margin
- margin-top
- margin-right
- margin-bottom
- margin-left
- padding
- padding-top
- padding-right
- padding-bottom
- padding-left
- background
- border
- border-radius
ignore-custom-properties: true

68
Gruntfile.js Normal file
View File

@ -0,0 +1,68 @@
module.exports = function(grunt) {
// time the grunt execution time
require('time-grunt')(grunt);
// configure main project settings
grunt.initConfig({
// basic config
pkg: grunt.file.readJSON('package.json'),
// CoffeeScript compiling
coffee: {
compile: {
options: {
sourceMap: false
},
expand: true,
flatten: true,
cwd: 'src/coffee',
src: '*.coffee',
dest: 'build/js',
ext: '.js'
}
},
// SASS compiling
sass: {
compile: {
options: {
style: 'compact'
},
files: [{
expand: true,
cwd: 'src/sass',
src: ['*.sass'],
dest: 'build/css',
ext: '.css'
}]
}
},
// watch sass and CoffeeScript files for live reloading
watch: {
scripts: {
files: [
'src/sass/*.sass',
'src/sass/*.scss',
'src/coffee/*.coffee'
],
tasks: ['sass', 'coffee'],
options: {
spawn: false
}
}
}
});
// load plugins
grunt.loadNpmTasks('grunt-contrib-coffee');
grunt.loadNpmTasks('grunt-contrib-sass');
grunt.loadNpmTasks('grunt-contrib-watch');
// do the tasks
grunt.registerTask('default', ['coffee', 'sass', 'watch']);
};

18
LICENSE
View File

@ -1,9 +1,9 @@
Copyright (c) <year> <owner>
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Copyright (c) 2018, Gregory Ballantine All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY Gregory Ballantine "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Gregory Ballantine BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,3 +1,85 @@
# metaunix-player-js
# Metaunix-Player.js
Open source video player for HTML sites
An HTML/Javascript video player - built as a jQuery plugin for easy use. The idea behind this project was to create an HTML5 video player that was very configurable and allowed for dynamic updates on a real website.
## Getting Started
Below you will learn how to get ready for an use this project.
### Prerequisites
#### Production
You simply need to include `<script>` tags that point to jQuery and a copy of the compiled Javascript files.
#### Development
You will need node.js installed on your machine to compile assets and run tests. You will need to install the Grunt CLI package with `npm install -g grunt-cli`. The rest of the tools required should be easily installed by running `npm install`
The list of tools installed will be:
* Grunt
* Grunt plugins for:
* Sass
* CoffeeScript
* Time (tracks how much time each task takes to run)
* Watch (for automatically re-running compilation steps)
* Sass-lint
### Usage
#### Production
Using this in a production environment (e.g. on a website), you will need to include this script, as stated above, create an HTML element, and then call the plugin in a second script, for example:
```html
<html>
<head>
<title>My Site</title>
<script src="https://cdn.example.com/path/to/jQuery"></script>
<script src="https://cdn.example.com/path/to/player.js"></script>
</head>
<body>
<div class="my-player" />
<script>
$('.my-player').MUPlayer({
'use_default_css': true,
'video_width': '720px',
'video_sources': [
{
'link': 'http://techslides.com/demos/sample-videos/small.ogv',
'type': 'video/ogg',
},
{
'link': 'http://techslides.com/demos/sample-videos/small.mp4',
'type': 'video/mp4',
}
]
});
</script>
</body>
</html>
```
#### Development
Assuming you have the grunt-cli NPM package installed, `cd` to a clone of this repository and run `grunt`. The SASS and CoffeeScript assets should now compile, and you can use the provided index.html file for local testing.
## Contributing
If you notice anything about this project that could be improved, feel free to open up an Issue, clone this repository and create a Pull Request with those changes, or shoot me an email at gballantine555@gmail.com.
Please, please, PLEASE be as detailed as possible if you notice any bugs or have feature requests. Copy the error/console output, suggest a possible way to implement a feature, give me something so I'm trying to tackle an issue blindly!
## Versioning
I will use [SemVer](http://semver.org/) for versioning this project - right now there are no versions available, but when I feel this project is ready to be used in any capacity, I'll start tagging releases.
## Authors
* **Gregory Ballantine** - [Gitea](https://git.metaunix.net/gballan)
## License
This project is licensed under the "Simplified" BSD License (aka BSD 2-Clause License) - see the LICENSE file for details

33
index.html Normal file
View File

@ -0,0 +1,33 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Metaunix Player Test</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="build/js/player.js"></script>
</head>
<body>
<!-- test video player wrapper -->
<div class="mup-player"></div>
<!-- call the player script -->
<script>
$('.mup-player').MUPlayer({
'use_default_css': true,
'video_width': '720px',
'video_sources': [
{
'link': 'http://techslides.com/demos/sample-videos/small.ogv',
'type': 'video/ogg',
},
{
'link': 'http://techslides.com/demos/sample-videos/small.mp4',
'type': 'video/mp4',
}
]
});
</script>
</body>
</html>

2179
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "metaunix-player",
"version": "0.1.0",
"description": "An HTML/Javascript video player",
"repository": {
"type": "git",
"url": "git@git.metaunix.net:gballan/metaunix-player-js.git"
},
"author": "Gregory Ballantine",
"license": "BSD-2-Clause",
"devDependencies": {
"grunt": "^1.0.2",
"grunt-contrib-coffee": "^2.0.0",
"grunt-contrib-sass": "^1.0.0",
"grunt-contrib-watch": "^1.0.0",
"sass-lint": "^1.12.1",
"time-grunt": "^1.4.0"
}
}

226
src/coffee/player.coffee Normal file
View File

@ -0,0 +1,226 @@
(($) ->
$.fn.MUPlayer = (opt) ->
# define global variables
settings = undefined # settings objects
videoElem = undefined
videoControls = undefined
volumeDragging = false
# combine user settings with defaults
settings = $.extend({
'use_default_css': false
'class_prefix': 'mup-'
'default_volume': 50
'default_position': 0
'video_sources': []
'video_width': false
}, opt)
## Functions
# setup - performs initial setup of the MUPlayer element
setup = (wrapperElem) ->
# add default CSS if needed
if settings.use_default_css
addStylesheet('build/css/mup.css')
# set player width
if typeof settings.video_width == 'string'
wrapperElem.width(settings.video_width)
# create the video player
createPlayer(wrapperElem)
# load the video now
videoElem.get(0).load()
# end setup function
return
# addStylesheet - adds a stylesheet to the head element
addStylesheet = (filename) ->
# create link element
cssElem = $('<link/>',
rel: 'stylesheet'
type: 'text/css'
href: filename)
# find stylesheet links
loadedStylesheets = $('head link[rel=stylesheet]')
# check if there are any loaded stylesheets
if loadedStylesheets.length > 0
# get last stylesheet
lastStylesheet = loadedStylesheets[loadedStylesheets.length - 1]
# append new stylesheet after the last one
lastStylesheet.after(cssElem)
else
# append the new element to the head element
$('head').append(cssElem)
# end addStylesheet function
return
# createPlayer - add HTML elements for the video player
createPlayer = (wrapperElem) ->
# create video element
videoElem = $('<video/>',
class: settings.class_prefix + 'video')
videoElem.on('ended', resetVideo)
videoElem.on('timeupdate', updateProgress)
videoElem.on('loadedmetadata', updateDuration)
videoElem.on('click', toggleIsPlaying)
# loop through the video sources
for source in settings.video_sources
# create new source element
newSrc = $('<source/>',
src: source.link
type: source.type)
# append source element to the newly created video element
videoElem.append(newSrc)
# create video controls wrapper
videoControls = $('<div/>',
class: settings.class_prefix + 'controls')
# create control elements
progressBar = $('<span/>',
class: settings.class_prefix + 'control' + ' ' +
settings.class_prefix + 'progress-bar').appendTo(videoControls)
progressFill = $('<span/>',
class: settings.class_prefix + 'control' + ' ' +
settings.class_prefix + 'progress-fill').appendTo(progressBar)
videoControlsLeft = $('<div/>',
class: settings.class_prefix + 'controls-left').appendTo(videoControls)
videoControlsRight = $('<div/>',
class: settings.class_prefix + 'controls-right').appendTo(videoControls)
playButton = $('<button/>',
class: settings.class_prefix + 'control' + ' ' +
settings.class_prefix + 'play-button'
text: '>').appendTo(videoControlsLeft)
playButton.on('click', (e) ->
e.preventDefault()
toggleIsPlaying())
progressTime = $('<div/>',
class: settings.class_prefix + 'control' + ' ' +
settings.class_prefix + 'progressTime').appendTo(videoControlsLeft)
progressTime.html('<span class="currentTime">' + msToTime(videoElem.get(0).currentTime) + '</span> / ' +
'<span class="totalTime">' + msToTime(videoElem.get(0).duration) + '</span>')
volumeSlider = $('<input/>',
class: settings.class_prefix + 'control' + ' ' +
settings.class_prefix + 'volume-slider'
type: 'range'
min: 0
max: 100
step: 1
).appendTo(videoControlsRight)
volumeSlider.on('input', ->
setVolume(this.value)
)
# add the elements to the player
$(wrapperElem).append(videoElem)
$(wrapperElem).append(videoControls)
# end createPlayer function
return
# playVideo - start playing video
playVideo = ->
videoElem.get(0).play()
videoControls.find('.' + settings.class_prefix + 'play-button').text('||')
isPlaying = true
# end playVideo function
return
# pauseVideo - pause video
pauseVideo = ->
videoElem.get(0).pause()
videoControls.find('.' + settings.class_prefix + 'play-button').text('>')
isPlaying = false
# end pauseVideo function
return
# resetVideo - reset the video back to the beginning
resetVideo = ->
pauseVideo()
updateProgress(0)
# toggleIsPlaying - toggle between play and pause
toggleIsPlaying = ->
if !videoElem.get(0).paused
pauseVideo()
else
playVideo()
# end toggleIsPlaying function
return
# setVolume - set the video player's volume
setVolume = (vol) ->
videoElem.get(0).volume = (vol / 100)
# updateProgress - perform actions when the video's progress updates
updateProgress = (setProgress = false) ->
# get the progress bar element
progressBar = videoControls.children('.' + settings.class_prefix + 'progress-bar')
progressFill = progressBar.children('.' + settings.class_prefix + 'progress-fill')
if typeof setProgress != 'number'
# calculate position in video as percentage
progress = videoElem.get(0).currentTime
else
progress = setProgress
# calculate width for the progress fill
progressWidth = (progress / videoElem.get(0).duration) * progressBar.width()
# set the width on the progress foreground element
progressFill.css('width', progressWidth + 'px')
# update the progress time while we're at it
videoControls.find('.currentTime').text(msToTime(progress))
# end updateProgress function
return
# updateDuration - updates the video's duration time
updateDuration = ->
currentTime = videoControls.find('.currentTime')
totalTime = videoControls.find('.totalTime')
currentTime.text(msToTime(videoElem.get(0).currentTime))
totalTime.text(msToTime(videoElem.get(0).duration))
# msToTime - converts seconds to a human-readable time
msToTime = (time) ->
secs = Math.floor(time % 60)
time = (time - secs) / 60
mins = Math.floor(time % 60)
hrs = Math.floor((time - mins) / 60)
if secs < 10
secs = '0' + secs
if hrs > 0 and mins < 10
mins = '0' + mins
if hrs > 0
return hrs + ':' + mins + ':' + secs
else
return mins + ':' + secs
# run the setup function
setup(this)
# end MUPlayer function
return
return
) jQuery

186
src/sass/mup.sass Normal file
View File

@ -0,0 +1,186 @@
//# general variables
$main-color: #f00
$background-color-dark: #212121
$control-background-light: #eee
$control-border: #212121
$shadow-color: #000
$text-color-dark: #212121
$text-color-white: #fff
//# slider variables
$slider-track-color: #808080
$slider-progress-color: $main-color
$slider-thumb-color: $main-color
$slider-thumb-height: calc(100% + 8px)
$slider-thumb-width: 15px
$slider-thumb-border-radius: 15px
//# styles
.mup-video
width: 100%
margin: 0
padding: 0
vertical-align: top
&:focus,
&:active
outline: none
.mup-controls
padding: 5px
background: $background-color-dark
overflow: auto
vertical-align: top
white-space: nowrap
input:focus
outline: none
button::-moz-focus-inner
border: none
.mup-controls-left
float: left
margin: 0
padding: 0
.mup-controls-right
float: right
margin: 0
padding: 0
.mup-control
display: inline-block
color: $text-color-white
&:not(:last-child)
margin-right: 10px
.mup-progress-bar,
.mup-progress-fill
margin: 0
padding: 0
border: none
.mup-control.mup-progress-bar
display: block
height: 8px
margin: 0 0 5px
padding: 0
background: $slider-track-color
.mup-progress-fill
display: block
width: 0
height: 100%
margin: 0
padding: 0
background: $main-color
button.mup-control
margin: 0
padding: 7px 12px
background: $control-background-light
border: none
color: $text-color-dark
font-size: 16px
font-weight: bold
transition: all 200ms ease-in-out
&:hover
background: lighten($control-background-light, 10%)
color: $text-color-dark
cursor: pointer
.mup-volume-slider
display: inline-block
width: 120px
height: 10px
margin: 10px 0 0
padding: 0
background: none
border: none
//# Chromium-based and Safari browser styles
&::-webkit-slider-runnable-track
width: 100%
height: 10px
background: $slider-track-color
border: none
border-radius: 25px
box-shadow: 0 0 0 $shadow-color, 0 0 0 $shadow-color
cursor: pointer
animate: 0.2s
overflow: hidden
&::-webkit-slider-thumb
width: $slider-thumb-width
height: $slider-thumb-height
margin-top: -2.4px
background: $main-color
border: none
border-radius: $slider-thumb-border-radius
box-shadow: -100px 0 0 90px $main-color
cursor: pointer
-webkit-appearance: none
&:focus::-webkit-slider-runnable-track
background: $slider-track-color
//# Mozilla browser styles for range
&::-moz-range-track
width: 100%
height: 10px
background: $slider-track-color
border: none
border-radius: 25px
box-shadow: 0 0 0 $shadow-color, 0 0 0 $shadow-color
cursor: pointer
animate: 0.2s
&::-moz-range-progress
height: 100%
background: $main-color
border-radius: $slider-thumb-border-radius
&::-moz-range-thumb
width: $slider-thumb-width
height: $slider-thumb-height
background: $main-color
border: none
border-radius: $slider-thumb-border-radius
box-shadow: 0 0 0 $shadow-color, 0 0 0 $shadow-color
cursor: pointer
//# Microsoft browser styles for range
&::-ms-track
width: 100%
height: 10px
background: transparent
border-color: transparent
border-width: 39px 0
color: transparent
cursor: pointer
animate: 0.2s
&::-ms-fill-lower,
&::-ms-fill-upper
background: $slider-track-color
border: none
border-radius: 50px
box-shadow: 0 0 0 $shadow-color, 0 0 0 $shadow-color
&::-ms-fill-lower
background: $slider-thumb-color
&::-ms-thumb
width: $slider-thumb-width
height: $slider-thumb-height
background: $main-color
border: none
border-radius: $slider-thumb-border-radius
box-shadow: 0 0 0 $shadow-color, 0 0 0 $shadow-color
cursor: pointer
&:focus
&::-ms-fill-lower, &::-ms-fill-upper
background: $main-color