├── .babelrc
├── .editorconfig
├── .gitignore
├── .travis.yml
├── assets
├── css
│ └── slider.css
├── images
│ └── bg.png
├── js
│ ├── slider.min.js
│ └── stickup.min.js
└── unslider
│ ├── css
│ ├── unslider-dots.css
│ └── unslider.css
│ └── js
│ └── unslider-min.js
├── demo
├── bangumi.html
├── bangumi_index.html
├── index.html
├── play.html
├── search.html
└── sort.html
├── docs
├── bh5.png
├── css
│ ├── main.css
│ └── slider.css
├── favicon.ico
├── img
│ ├── bg0.png
│ └── bg1.jpg
├── index.html
└── js
│ ├── app.js
│ ├── slider.min.js
│ └── stickup.min.js
├── favicon.ico
├── gulpfile.babel.js
├── package.json
├── readme.md
└── src
├── images
├── bg0.png
└── bg1.jpg
├── index.html
├── js
├── App.js
├── Config.js
├── Index.js
├── components
│ ├── AllRank.js
│ ├── BangumiIndex.js
│ ├── BangumiInfo.js
│ ├── BangumiList.js
│ ├── IndexBanner.js
│ ├── IndexHot.js
│ ├── Loading.js
│ ├── Pager.js
│ ├── Player.js
│ ├── SearchContent.js
│ ├── SortHot.js
│ ├── SortRank.js
│ └── Video.js
├── danmaku
│ ├── BilibiliParser.js
│ ├── CommentManager.js
│ ├── CommentObject.js
│ ├── ScrollComment.js
│ ├── StaticComment.js
│ └── VideojsPlugin.js
├── page
│ ├── BangumiIndexPage.js
│ ├── BangumiInfoPage.js
│ ├── IndexPage.js
│ ├── SearchPage.js
│ ├── SortPage.js
│ └── ViewPage.js
├── parts
│ ├── Error.js
│ ├── Footer.js
│ └── Loading.js
└── utils
│ └── VideojsHotKeys.js
└── styles
├── bangumi.css
├── main.css
└── player.css
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | "es2015",
4 | "react"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent
2 | # coding styles between different editors and IDEs
3 | # editorconfig.org
4 |
5 | root = true
6 |
7 |
8 | [*]
9 |
10 | # Change these settings to your own preference
11 | indent_style = space
12 | indent_size = 2
13 |
14 | # We recommend you to keep these unchanged
15 | end_of_line = lf
16 | charset = utf-8
17 | trim_trailing_whitespace = true
18 | insert_final_newline = true
19 |
20 | [*.md]
21 | trim_trailing_whitespace = false
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
3 | .tmp
4 |
5 | .idea
6 |
7 | dist
8 |
9 | .publish
10 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - "5.0.0"
4 | - "4.0.0"
5 |
--------------------------------------------------------------------------------
/assets/css/slider.css:
--------------------------------------------------------------------------------
1 | .unslider{overflow:auto;margin:0;padding:0}.unslider-wrap{position:relative}.unslider-wrap.unslider-carousel>li{float:left}.unslider-vertical>ul{height:100%}.unslider-vertical li{float:none;width:100%}.unslider-fade{position:relative}.unslider-fade .unslider-wrap li{position:absolute;left:0;top:0;right:0;z-index:8}.unslider-fade .unslider-wrap li.unslider-active{z-index:10}.unslider li,.unslider ol,.unslider ul{list-style:none;margin:0;padding:0;border:none}.unslider-arrow{position:absolute;left:20px;z-index:2;cursor:pointer}.unslider-arrow.next{left:auto;right:20px}
--------------------------------------------------------------------------------
/assets/images/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/assets/images/bg.png
--------------------------------------------------------------------------------
/assets/js/slider.min.js:
--------------------------------------------------------------------------------
1 | !function($){return $?($.Unslider=function(t,n){var e=this;return e._="unslider",e.defaults={autoplay:!1,delay:3e3,speed:750,easing:"swing",keys:{prev:37,next:39},nav:!0,arrows:{prev:'Prev',next:'Next'},animation:"horizontal",selectors:{container:"ul:first",slides:"li"},animateHeight:!1,activeClass:e._+"-active",swipe:!0,swipeThreshold:.2},e.$context=t,e.options={},e.$parent=null,e.$container=null,e.$slides=null,e.$nav=null,e.$arrows=[],e.total=0,e.current=0,e.prefix=e._+"-",e.eventSuffix="."+e.prefix+~~(2e3*Math.random()),e.interval=null,e.init=function(t){return e.options=$.extend({},e.defaults,t),e.$container=e.$context.find(e.options.selectors.container).addClass(e.prefix+"wrap"),e.$slides=e.$container.children(e.options.selectors.slides),e.setup(),$.each(["nav","arrows","keys","infinite"],function(t,n){e.options[n]&&e["init"+$._ucfirst(n)]()}),jQuery.event.special.swipe&&e.options.swipe&&e.initSwipe(),e.options.autoplay&&e.start(),e.calculateSlides(),e.$context.trigger(e._+".ready"),e.animate(e.options.index||e.current,"init")},e.setup=function(){e.$context.addClass(e.prefix+e.options.animation).wrap('
'),e.$parent=e.$context.parent("."+e._);var t=e.$context.css("position");"static"===t&&e.$context.css("position","relative"),e.$context.css("overflow","hidden")},e.calculateSlides=function(){if(e.total=e.$slides.length,"fade"!==e.options.animation){var t="width";"vertical"===e.options.animation&&(t="height"),e.$container.css(t,100*e.total+"%").addClass(e.prefix+"carousel"),e.$slides.css(t,100/e.total+"%")}},e.start=function(){return e.interval=setTimeout(function(){e.next()},e.options.delay),e},e.stop=function(){return clearTimeout(e.interval),e},e.initNav=function(){var t=$('');e.$slides.each(function(n){var i=this.getAttribute("data-nav")||n+1;$.isFunction(e.options.nav)&&(i=e.options.nav.call(e.$slides.eq(n),n,i)),t.children("ol").append(''+i+"")}),e.$nav=t.insertAfter(e.$context),e.$nav.find("li").on("click"+e.eventSuffix,function(){var t=$(this).addClass(e.options.activeClass);t.siblings().removeClass(e.options.activeClass),e.animate(t.attr("data-slide"))})},e.initArrows=function(){e.options.arrows===!0&&(e.options.arrows=e.defaults.arrows),$.each(e.options.arrows,function(t,n){e.$arrows.push($(n).insertAfter(e.$context).on("click"+e.eventSuffix,e[t]))})},e.initKeys=function(){e.options.keys===!0&&(e.options.keys=e.defaults.keys),$(document).on("keyup"+e.eventSuffix,function(t){$.each(e.options.keys,function(n,i){t.which===i&&$.isFunction(e[n])&&e[n].call(e)})})},e.initSwipe=function(){var t=e.$slides.width();"fade"!==e.options.animation&&e.$container.on({movestart:function(t){return t.distX>t.distY&&t.distX<-t.distY||t.distX-t.distY?!!t.preventDefault():void e.$container.css("position","relative")},move:function(n){e.$container.css("left",-(100*e.current)+100*n.distX/t+"%")},moveend:function(n){Math.abs(n.distX)/t>e.options.swipeThreshold?e[n.distX<0?"next":"prev"]():e.$container.animate({left:-(100*e.current)+"%"},e.options.speed/2)}})},e.initInfinite=function(){var t=["first","last"];$.each(t,function(n,i){e.$slides.push.apply(e.$slides,e.$slides.filter(':not(".'+e._+'-clone")')[i]().clone().addClass(e._+"-clone")["insert"+(0===n?"After":"Before")](e.$slides[t[~~!n]]()))})},e.destroyArrows=function(){$.each(e.$arrows,function(t,n){n.remove()})},e.destroySwipe=function(){e.$container.off("movestart move moveend")},e.destroyKeys=function(){$(document).off("keyup"+e.eventSuffix)},e.setIndex=function(t){return 0>t&&(t=e.total-1),e.current=Math.min(Math.max(0,t),e.total-1),e.options.nav&&e.$nav.find('[data-slide="'+e.current+'"]')._active(e.options.activeClass),e.$slides.eq(e.current)._active(e.options.activeClass),e},e.animate=function(t,n){if("first"===t&&(t=0),"last"===t&&(t=e.total),isNaN(t))return e;e.options.autoplay&&e.stop().start(),e.setIndex(t),e.$context.trigger(e._+".change",[t,e.$slides.eq(t)]);var i="animate"+$._ucfirst(e.options.animation);return $.isFunction(e[i])&&e[i](e.current,n),e},e.next=function(){var t=e.current+1;return t>=e.total&&(t=0),e.animate(t,"next")},e.prev=function(){return e.animate(e.current-1,"prev")},e.animateHorizontal=function(t){var n="left";return"rtl"===e.$context.attr("dir")&&(n="right"),e.options.infinite&&e.$container.css("margin-"+n,"-100%"),e.slide(n,t)},e.animateVertical=function(t){return e.options.animateHeight=!0,e.options.infinite&&e.$container.css("margin-top",-e.$slides.outerHeight()),e.slide("top",t)},e.slide=function(t,n){if(e.options.animateHeight&&e._move(e.$context,{height:e.$slides.eq(n).outerHeight()},!1),e.options.infinite){var i;n===e.total-1&&(i=e.total-3,n=-1),n===e.total-2&&(i=0,n=e.total-2),"number"==typeof i&&(e.setIndex(i),e.$context.on(e._+".moved",function(){e.current===i&&e.$container.css(t,-(100*i)+"%").off(e._+".moved")}))}var o={};return o[t]=-(100*n)+"%",e._move(e.$container,o)},e.animateFade=function(t){var n=e.$slides.eq(t).addClass(e.options.activeClass);e._move(n.siblings().removeClass(e.options.activeClass),{opacity:0}),e._move(n,{opacity:1},!1)},e._move=function(t,n,i,o){return i!==!1&&(i=function(){e.$context.trigger(e._+".moved")}),t._move(n,o||e.options.speed,e.options.easing,i)},e.init(n)},$.fn._active=function(t){return this.addClass(t).siblings().removeClass(t)},$._ucfirst=function(t){return(t+"").toLowerCase().replace(/^./,function(t){return t.toUpperCase()})},$.fn._move=function(){return this.stop(!0,!0),$.fn[$.fn.velocity?"velocity":"animate"].apply(this,arguments)},void($.fn.unslider=function(t){return this.each(function(){var n=$(this);if("string"==typeof t&&n.data("unslider")){t=t.split(":");var e=n.data("unslider")[t[0]];if($.isFunction(e))return e.apply(n,t[1]?t[1].split(","):null)}return n.data("unslider",new $.Unslider(n,t))})})):console.warn("Unslider needs jQuery")}(window.jQuery);
--------------------------------------------------------------------------------
/assets/js/stickup.min.js:
--------------------------------------------------------------------------------
1 | jQuery(function(t){"use strict";var e=function(){},o={},n=0;e.prototype={dataProperty:"data-menu",itemClass:"",itemHover:"",marginTop:0,beforeStick:null,afterStick:null,beforeUnstick:null,afterUnstick:null,region:"top",_selector:"",_jqDom:null,_menuItems:[],_height:0,_parentMarginTop:0,_top:0,_marginBottom:0,onScroll:function(e,o){var n=null,r=null,i=this;if(i._menuItems&&i._menuItems.length>0)for(var a=null,s=0,m=null,l=0;ls-50&&s+50>o&&(i._jqDom.find("."+i.itemClass).removeClass(i.itemHover),i._jqDom.find("."+i.itemClass+":eq("+l+")").addClass(i.itemHover)),"up"==e&&(n=.4*m.height(),r=s-n,o>r?(i._jqDom.find("."+i.itemClass).removeClass(i.itemHover),i._jqDom.find("."+i.itemClass+":eq("+l+")").addClass(i.itemHover)):50>o&&(i._jqDom.find("."+i.itemClass).removeClass(i.itemHover),i._jqDom.find("."+i.itemClass+":eq(0)").addClass(i.itemHover)));i._top0?a.marginTop=parseInt(r.topMargin.replace("px","")):isNaN(parseInt(r.topMargin))?(console.log("incorrect argument, ignored."),a.marginTop=0):a.marginTop=parseInt(r.topMargin):a.marginTop=0,a.itemClass=r.itemClass,a.itemHover=r.itemHover):console.log("warm:needs arguments"),a.dataProperty=r.dataProperty||a.dataProperty,a.region=r.region||a.region,a._height=parseInt(a._jqDom.height()),a._marginBottom=parseInt(a._jqDom.css("margin-bottom")),a._parentMarginTop=parseInt(a._jqDom.next().closest("div").css("margin-top")),a._top=parseInt(a._jqDom.offset().top),o[a._selector]=a},t.fn.stickUp=function(t){o[this.selector]||e._init_(this,t)},t(document).on("scroll",function(){var e=parseInt(t(document).scrollTop()),r=e>n?"down":"up";for(var i in o)o[i].onScroll(r,e);n=e})});
--------------------------------------------------------------------------------
/assets/unslider/css/unslider-dots.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Here's where everything gets included. You don't need
3 | * to change anything here, and doing so might break
4 | * stuff. Here be dragons and all that.
5 | */
6 | /**
7 | * Default variables
8 | *
9 | * While these can be set with JavaScript, it's probably
10 | * better and faster to just set them here, compile to
11 | * CSS and include that instead to use some of that
12 | * hardware-accelerated goodness.
13 | */
14 | .unslider-nav ol {
15 | list-style: none;
16 | text-align: center;
17 | }
18 | .unslider-nav ol li {
19 | display: inline-block;
20 | width: 6px;
21 | height: 6px;
22 | margin: 0 4px;
23 | background: transparent;
24 | border-radius: 5px;
25 | overflow: hidden;
26 | text-indent: -999em;
27 | border: 2px solid #fff;
28 | cursor: pointer;
29 | }
30 | .unslider-nav ol li.unslider-active {
31 | background: #fff;
32 | cursor: default;
33 | }
34 |
--------------------------------------------------------------------------------
/assets/unslider/css/unslider.css:
--------------------------------------------------------------------------------
1 | .unslider{overflow:auto;margin:0;padding:0}.unslider-wrap{position:relative}.unslider-wrap.unslider-carousel>li{float:left}.unslider-vertical>ul{height:100%}.unslider-vertical li{float:none;width:100%}.unslider-fade{position:relative}.unslider-fade .unslider-wrap li{position:absolute;left:0;top:0;right:0;z-index:8}.unslider-fade .unslider-wrap li.unslider-active{z-index:10}.unslider li,.unslider ol,.unslider ul{list-style:none;margin:0;padding:0;border:none}.unslider-arrow{position:absolute;left:20px;z-index:2;cursor:pointer}.unslider-arrow.next{left:auto;right:20px}
--------------------------------------------------------------------------------
/assets/unslider/js/unslider-min.js:
--------------------------------------------------------------------------------
1 | !function($){return $?($.Unslider=function(t,n){var e=this;return e._="unslider",e.defaults={autoplay:!1,delay:3e3,speed:750,easing:"swing",keys:{prev:37,next:39},nav:!0,arrows:{prev:'Prev',next:'Next'},animation:"horizontal",selectors:{container:"ul:first",slides:"li"},animateHeight:!1,activeClass:e._+"-active",swipe:!0,swipeThreshold:.2},e.$context=t,e.options={},e.$parent=null,e.$container=null,e.$slides=null,e.$nav=null,e.$arrows=[],e.total=0,e.current=0,e.prefix=e._+"-",e.eventSuffix="."+e.prefix+~~(2e3*Math.random()),e.interval=null,e.init=function(t){return e.options=$.extend({},e.defaults,t),e.$container=e.$context.find(e.options.selectors.container).addClass(e.prefix+"wrap"),e.$slides=e.$container.children(e.options.selectors.slides),e.setup(),$.each(["nav","arrows","keys","infinite"],function(t,n){e.options[n]&&e["init"+$._ucfirst(n)]()}),jQuery.event.special.swipe&&e.options.swipe&&e.initSwipe(),e.options.autoplay&&e.start(),e.calculateSlides(),e.$context.trigger(e._+".ready"),e.animate(e.options.index||e.current,"init")},e.setup=function(){e.$context.addClass(e.prefix+e.options.animation).wrap(''),e.$parent=e.$context.parent("."+e._);var t=e.$context.css("position");"static"===t&&e.$context.css("position","relative"),e.$context.css("overflow","hidden")},e.calculateSlides=function(){if(e.total=e.$slides.length,"fade"!==e.options.animation){var t="width";"vertical"===e.options.animation&&(t="height"),e.$container.css(t,100*e.total+"%").addClass(e.prefix+"carousel"),e.$slides.css(t,100/e.total+"%")}},e.start=function(){return e.interval=setTimeout(function(){e.next()},e.options.delay),e},e.stop=function(){return clearTimeout(e.interval),e},e.initNav=function(){var t=$('');e.$slides.each(function(n){var i=this.getAttribute("data-nav")||n+1;$.isFunction(e.options.nav)&&(i=e.options.nav.call(e.$slides.eq(n),n,i)),t.children("ol").append(''+i+"")}),e.$nav=t.insertAfter(e.$context),e.$nav.find("li").on("click"+e.eventSuffix,function(){var t=$(this).addClass(e.options.activeClass);t.siblings().removeClass(e.options.activeClass),e.animate(t.attr("data-slide"))})},e.initArrows=function(){e.options.arrows===!0&&(e.options.arrows=e.defaults.arrows),$.each(e.options.arrows,function(t,n){e.$arrows.push($(n).insertAfter(e.$context).on("click"+e.eventSuffix,e[t]))})},e.initKeys=function(){e.options.keys===!0&&(e.options.keys=e.defaults.keys),$(document).on("keyup"+e.eventSuffix,function(t){$.each(e.options.keys,function(n,i){t.which===i&&$.isFunction(e[n])&&e[n].call(e)})})},e.initSwipe=function(){var t=e.$slides.width();"fade"!==e.options.animation&&e.$container.on({movestart:function(t){return t.distX>t.distY&&t.distX<-t.distY||t.distX-t.distY?!!t.preventDefault():void e.$container.css("position","relative")},move:function(n){e.$container.css("left",-(100*e.current)+100*n.distX/t+"%")},moveend:function(n){Math.abs(n.distX)/t>e.options.swipeThreshold?e[n.distX<0?"next":"prev"]():e.$container.animate({left:-(100*e.current)+"%"},e.options.speed/2)}})},e.initInfinite=function(){var t=["first","last"];$.each(t,function(n,i){e.$slides.push.apply(e.$slides,e.$slides.filter(':not(".'+e._+'-clone")')[i]().clone().addClass(e._+"-clone")["insert"+(0===n?"After":"Before")](e.$slides[t[~~!n]]()))})},e.destroyArrows=function(){$.each(e.$arrows,function(t,n){n.remove()})},e.destroySwipe=function(){e.$container.off("movestart move moveend")},e.destroyKeys=function(){$(document).off("keyup"+e.eventSuffix)},e.setIndex=function(t){return 0>t&&(t=e.total-1),e.current=Math.min(Math.max(0,t),e.total-1),e.options.nav&&e.$nav.find('[data-slide="'+e.current+'"]')._active(e.options.activeClass),e.$slides.eq(e.current)._active(e.options.activeClass),e},e.animate=function(t,n){if("first"===t&&(t=0),"last"===t&&(t=e.total),isNaN(t))return e;e.options.autoplay&&e.stop().start(),e.setIndex(t),e.$context.trigger(e._+".change",[t,e.$slides.eq(t)]);var i="animate"+$._ucfirst(e.options.animation);return $.isFunction(e[i])&&e[i](e.current,n),e},e.next=function(){var t=e.current+1;return t>=e.total&&(t=0),e.animate(t,"next")},e.prev=function(){return e.animate(e.current-1,"prev")},e.animateHorizontal=function(t){var n="left";return"rtl"===e.$context.attr("dir")&&(n="right"),e.options.infinite&&e.$container.css("margin-"+n,"-100%"),e.slide(n,t)},e.animateVertical=function(t){return e.options.animateHeight=!0,e.options.infinite&&e.$container.css("margin-top",-e.$slides.outerHeight()),e.slide("top",t)},e.slide=function(t,n){if(e.options.animateHeight&&e._move(e.$context,{height:e.$slides.eq(n).outerHeight()},!1),e.options.infinite){var i;n===e.total-1&&(i=e.total-3,n=-1),n===e.total-2&&(i=0,n=e.total-2),"number"==typeof i&&(e.setIndex(i),e.$context.on(e._+".moved",function(){e.current===i&&e.$container.css(t,-(100*i)+"%").off(e._+".moved")}))}var o={};return o[t]=-(100*n)+"%",e._move(e.$container,o)},e.animateFade=function(t){var n=e.$slides.eq(t).addClass(e.options.activeClass);e._move(n.siblings().removeClass(e.options.activeClass),{opacity:0}),e._move(n,{opacity:1},!1)},e._move=function(t,n,i,o){return i!==!1&&(i=function(){e.$context.trigger(e._+".moved")}),t._move(n,o||e.options.speed,e.options.easing,i)},e.init(n)},$.fn._active=function(t){return this.addClass(t).siblings().removeClass(t)},$._ucfirst=function(t){return(t+"").toLowerCase().replace(/^./,function(t){return t.toUpperCase()})},$.fn._move=function(){return this.stop(!0,!0),$.fn[$.fn.velocity?"velocity":"animate"].apply(this,arguments)},void($.fn.unslider=function(t){return this.each(function(){var n=$(this);if("string"==typeof t&&n.data("unslider")){t=t.split(":");var e=n.data("unslider")[t[0]];if($.isFunction(e))return e.apply(n,t[1]?t[1].split(","):null)}return n.data("unslider",new $.Unslider(n,t))})})):console.warn("Unslider needs jQuery")}(window.jQuery);
--------------------------------------------------------------------------------
/demo/bangumi.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
58 |
59 |
60 |
61 |
76 |
77 |
78 |
79 |
80 |
81 |

82 |
83 |
84 |
FATE/EXTRA
85 |
Fate(フェイト)系列作品最早的是由TYPE-MOON于2004年1月30日发售的PC平台18禁文字冒险游戏《Fate/stay
86 | night》,同时也是TYPE-MOON商业化后初次亮相的作品。由于广受欢迎,吸引了一些作家参与制作,由本篇衍生诸多人气作品。
87 |
88 |
播放: 2333
89 |
收藏: 333
90 |
更新时间:2013-02-16
91 |
92 |
93 |
94 |
95 |
96 |
97 |

98 |
99 |
100 |
FATE/EXTRA
101 |
Fate(フェイト)系列作品最早的是由TYPE-MOON于2004年1月30日发售的PC平台18禁文字冒险游戏《Fate/stay
102 | night》,同时也是TYPE-MOON商业化后初次亮相的作品。由于广受欢迎,吸引了一些作家参与制作,由本篇衍生诸多人气作品。
103 |
104 |
播放: 2333
105 |
收藏: 333
106 |
更新时间:2013-02-16
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
剧集:
116 |
117 | - 1
118 | - 1
119 | - 1
120 | - 1
121 | - 1
122 | - 1
123 | - 1
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
139 |
140 |
141 |
142 |
--------------------------------------------------------------------------------
/demo/bangumi_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
58 |
59 |
60 |
61 |
74 |
75 |
76 |
77 |
78 |
番剧推荐
79 |
80 |
81 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
番剧列表
112 |
113 |
138 |
139 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
169 |
170 |
171 |
172 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
59 |
60 |
61 |
62 |
63 |
64 |
86 |
87 |
88 |
102 |
103 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
135 |
136 |
137 |
138 |
156 |
157 |
175 |
176 |
194 |
195 |
213 |
214 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
252 |
253 |
265 |
266 |
267 |
268 |
269 |
297 |
298 |
299 |
300 |
301 |
302 |
314 |
315 |
316 |
317 |
--------------------------------------------------------------------------------
/demo/play.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
24 |
25 |
26 |
27 |
28 |
29 |
31 |
32 |
33 |
34 | -
35 | 首页
36 |
37 |
38 | -
39 | 分类
40 |
44 |
45 |
46 | -
47 | 新番
48 |
49 |
50 | -
51 | 移动端
52 |
53 |
54 | -
55 | 项目
56 |
57 |
58 | -
59 | 关于
60 |
61 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
【4月】黑色残骸 05【生肉】
79 |
80 |
81 |
82 |
分类: 连载动画
83 |
时间: 2016-05-05 21:50
84 |
85 |
86 |
87 |
88 |
播放: 23233
89 |
弹幕: 2333
90 |
硬币: 23
91 |
92 |
93 |
94 |
95 |
96 |
100 |
101 |
八云境界
102 |
【F宅字幕组】【群:233862998】~境界无处不在~~我与你之间的境界在哪呢~
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 | 1、失去的存在
114 |
115 |
116 |
117 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
132 |
133 |
~ 第5話 「学び舎に来た男」
134 |
135 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
173 |
174 |
175 |
176 |
177 |
178 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/demo/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
搜索
66 |
67 |
68 |
69 |
70 |
71 | - 视频
72 | - 番剧
73 | - 专题
74 | - UP主
75 |
76 |
77 |
78 |
79 |
80 |
81 | - 综合排序
82 | - 最多点击
83 | - 最新发布
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |

95 |
96 |
97 |
FATE/EXTRA
98 |
Fate(フェイト)系列作品最早的是由TYPE-MOON于2004年1月30日发售的PC平台18禁文字冒险游戏《Fate/stay
99 | night》,同时也是TYPE-MOON商业化后初次亮相的作品。由于广受欢迎,吸引了一些作家参与制作,由本篇衍生诸多人气作品。
100 |
101 |
播放: 2333
102 |
收藏: 333
103 |
更新时间:2013-02-16
104 |
105 |
106 |
107 |
108 |
109 |
110 |

111 |
112 |
113 |
FATE/EXTRA
114 |
Fate(フェイト)系列作品最早的是由TYPE-MOON于2004年1月30日发售的PC平台18禁文字冒险游戏《Fate/stay
115 | night》,同时也是TYPE-MOON商业化后初次亮相的作品。由于广受欢迎,吸引了一些作家参与制作,由本篇衍生诸多人气作品。
116 |
117 |
播放: 2333
118 |
收藏: 333
119 |
更新时间:2013-02-16
120 |
121 |
122 |
123 |
124 |
140 |
141 |
157 |
158 |
174 |
175 |
191 |
192 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
223 |
224 |
225 |
226 |
--------------------------------------------------------------------------------
/demo/sort.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Title
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 | -
21 | 首页
22 |
23 |
24 | -
25 | 分类
26 |
30 |
31 |
32 | -
33 | 新番
34 |
35 |
36 | -
37 | 移动端
38 |
39 |
40 | -
41 | 项目
42 |
43 |
44 | -
45 | 关于
46 |
47 |
48 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
65 |
69 |
70 |
71 |
96 |
97 |
98 |
99 |
111 |
112 |
113 |
114 |
115 |
118 |
119 |
120 |
121 |

122 |
123 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
148 |
149 |
150 |
151 |
--------------------------------------------------------------------------------
/docs/bh5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/docs/bh5.png
--------------------------------------------------------------------------------
/docs/css/main.css:
--------------------------------------------------------------------------------
1 | .bangumi-banner-block{margin:20px auto;width:640px;height:200px;position:relative;overflow:hidden}.bangumi-banner{width:640px;height:200px}.area-banner>h2{margin:20px 10px;font-size:25px;font-weight:700;color:#666}.bangumi_item{width:200px;height:120px;margin:10px 20px;border-radius:4px;border:1px solid #f6f6f6;overflow:hidden;-webkit-transition:border .2s ease;-moz-transition:border .2s ease;-ms-transition:border .2s ease;-o-transition:border .2s ease;transition:border .2s ease}.bangumi_item:hover{border:1px solid #666;box-shadow:0 0 5px #b3b2b2}.bangumi_item:hover>.info>.title{color:#e04270}.bangumi_item>.img-small{width:99px;height:119px;overflow:hidden}.bangumi_item>.info{width:99px;height:119px;padding:0 5px;overflow:hidden}.bangumi_item>.info>.title{display:block;padding:5px 5px;position:relative;font-size:13px;font-weight:700;color:#000;height:60px;overflow:hidden}.bangumi_item>.info>.other{display:block;padding:10px 5px;position:relative;font-size:11px;font-weight:700;color:#666;max-height:50px;overflow:hidden}.img-small>img{width:100%}.list-bangumi-block{width:960px;max-height:140px;overflow:hidden;margin:20px auto}.toggle-btn{width:100px;height:30px;margin:10px auto;border-radius:4px;border:1px solid #666}.toggle-btn>a{display:block;text-align:center;margin:5px auto;font-size:13px;font-weight:700;color:#555}.toggle-btn>a:hover{color:#e04270}.bangumi-header{width:1000px;min-height:400px;margin:20px auto;background-color:#fff}.bangumi-header>h2{display:block;position:relative;left:150px;top:25px;width:600px;color:#525659;overflow:hidden;line-height:24px;text-overflow:ellipsis;font-weight:400;white-space:nowrap;font-size:20px}.bangumi-header-img{float:left;position:relative;left:50px;top:25px;width:200px;height:293px}.bangumi-header-img>img{width:200px}.bangumi-header-info{float:left;position:relative;left:150px;top:80px;width:600px;min-height:250px;color:#666;font-weight:700}.bangumi-header-info>p{font-size:14px;line-height:150%;font-weight:100}.bangumi-header-info>span{font-size:14px;line-height:150%;font-weight:100}.bangumi-part{background-color:#fff;width:1000px;min-height:200px}.bangumi-part>ul{margin:0 0;position:relative;top:40px;left:35px;width:90%}.bangumi-part>p{position:relative;top:20px;left:30px;font-size:25px;font-weight:700;color:#666}.bangumi-part>ul>li{display:block;margin:5px 10px;min-width:64px;padding:0 5px;height:32px;border:1px solid #999;border-radius:4px;-webkit-transition:background-color .2s ease;-moz-transition:background-color .2s ease;-ms-transition:background-color .2s ease;-o-transition:background-color .2s ease;transition:background-color .2s ease}.bangumi-part>ul>li>a{display:block;height:32px;text-decoration:none;text-align:center}.bangumi-part>ul>li:hover{background-color:#aeb7bf}.bangumi-part-span{text-decoration:none;color:#999;position:relative;top:6px}.bangumi-part>ul>li:hover .video_more_span{color:#fff}.bangumi-season{background-color:#fff;margin:20px auto;padding:0 10px;width:1000px}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;margin:0 auto;padding:0;outline:0;border:0;vertical-align:baseline;font-weight:inherit;font-style:inherit;font-size:100%;font-family:inherit;zoom:1}a{color:#369;text-decoration:none;white-space:normal;word-break:break-all;cursor:pointer;font-size:12px;font-weight:400}body{background-color:#f6f6f6;position:static;font-size:12px;font-family:"Helvetica Neue",Helvetica,Arial,STHeiti,"Microsoft Yahei",sans-serif;line-height:16px;-webkit-font-smoothing:antialiased}.clear{clear:both}.floatleft{position:relative;float:left}.floatright{position:relative;float:right}#main-container{width:100%;margin:40px 0 0 0;padding:0}#main-container.concat{margin-top:0}#main-container>#index-head-area{padding-top:26px}.area{position:relative}.area-inner{width:980px;margin:0 auto}.area-banner{position:relative;width:auto;height:36px;color:#666;text-align:left;font-size:14px;line-height:34px;zoom:1;margin:0;padding:0}.area-banner-ch{position:relative;margin-right:10px;display:inline-block}.area-banner-ch>h3{display:block;font-size:16px;letter-spacing:.06em;font-weight:400;color:#fff;background-color:#00a1d6;padding:0 24px;height:26px;line-height:26px;border-radius:6px}.area-banner-line-left{position:absolute;width:50%;height:7px;bottom:-7px;background-color:#f6f6f6;z-index:2;left:0;border-right:1px solid #00a1d6}.area-banner-line-right{display:block;position:absolute;width:100%;border-top:1px solid #00a1d6;font-size:14px}.area-banner-line-circle{position:absolute;width:6px;height:6px;background-color:#ffa5c7;right:0;bottom:-1px}.list-video-block{margin:20px auto}.list-video-block>.video-block{margin:10px 18px}.video-block{width:160px;height:145px;overflow:hidden}.video-block-main{display:block;width:160px;height:90px;overflow:hidden}.video-block-main>img{width:160px;height:100%;border-radius:16px 12px 12px 12px}.video-block-info{-webkit-transition:color .2s ease,height .2s ease;-moz-transition:color .2s ease,height .2s ease;-ms-transition:color .2s ease,height .2s ease;-o-transition:color .2s ease,height .2s ease;transition:color .2s ease,height .2s ease;display:block;width:100%;margin:8px 0;font-size:12px;color:#000;line-height:16px;height:18px;overflow:hidden}.video-block-time{-webkit-transition:opacity .2s ease;-moz-transition:opacity .2s ease;-ms-transition:opacity .2s ease;-o-transition:opacity .2s ease;transition:opacity .2s ease;position:absolute;color:#fff;background-color:rgba(0,0,0,.7);padding:0 5px;top:72px;right:0;height:18px;overflow:hidden;opacity:0;border-radius:0 0 12px 0}.video-block:hover .video-block-time{opacity:1}.video-block-info-hidden{color:#999;height:24px;line-height:24px;overflow:hidden;font-size:11px;top:114px;left:0}.video-block:hover .video-block-info{height:32px}.video-block-info-hidden>.left{margin-left:2px}.video-block-info-hidden>.right{margin-right:2px}.video-block-info:hover{color:#ffa5c7}.video-block-info:visited{color:#888}.video-block-mask{width:160px;height:100px;overflow:hidden}.video-block-mask-preview{height:100px;background:0;overflow:hidden;border-radius:4px}.video-block-mask-preview>img{height:100%;margin:0 auto;display:block}.video-block-mask-mask{position:absolute;width:100%;height:100%;opacity:0;visibility:hidden;top:0;left:0;background:#000;background:rgba(0,0,0,.7);filter:alpha(opacity=70);z-index:1;transition:.3s all linear;border-radius:4px}.video-block-mask:hover .video-block-mask-mask{visibility:visible;opacity:1}.video-block-mask-info{height:30px;padding:0;overflow:hidden;position:absolute;top:70px;width:100%;bottom:0;left:0;z-index:1;background:-webkit-linear-gradient(transparent,rgba(0,0,0,.1) 20%,rgba(0,0,0,.2) 35%,rgba(0,0,0,.6) 65%,rgba(0,0,0,.9));background:-o-linear-gradient(transparent,rgba(0,0,0,.1) 20%,rgba(0,0,0,.2) 35%,rgba(0,0,0,.6) 65%,rgba(0,0,0,.9));background:-moz-linear-gradient(transparent,rgba(0,0,0,.1) 20%,rgba(0,0,0,.2) 35%,rgba(0,0,0,.6) 65%,rgba(0,0,0,.9));background:linear-gradient(transparent,rgba(0,0,0,.1) 20%,rgba(0,0,0,.2) 35%,rgba(0,0,0,.6) 65%,rgba(0,0,0,.9));border-radius:0 0 4px 4px}.video-block-mask:hover .video-block-mask-info{top:0;height:70px;background:0 0}.video-block-mask:hover .play,.video-block-mask:hover .up{opacity:1}.video-block-mask-info>.title{height:36px;margin:10px 5px 0 5px;line-height:18px;overflow:hidden;color:#fff;font-size:12px;word-break:break-all;word-wrap:break-word}.video-block-mask-info>.up{margin:10px 0 5px 5px}.video-block-mask-info>.play{margin:5px 5px 0}.video-block-mask-info>.play,.video-block-mask-info>.up{color:#99a2aa;transition:.4s all linear;opacity:0;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}#main-header{z-index:2;width:100%}#main-header.hidden-background .main-header-image{display:none}.main-header-nav{background-color:#fff;border-bottom:1px solid #ffa5c7;-webkit-box-shadow:0 1px 8px rgba(0,0,0,.3);box-shadow:0 1px 8px rgba(0,0,0,.3)}.main-header-nav-body{height:50px;width:980px;margin:0 auto}.main-header-nav-body>.nav-li{position:relative;font-size:14px;display:block;height:50px}.nav-li>a{color:#222;display:block;font-size:14px;margin:15px 20px auto 20px}.nav-li>a:hover{color:#00a1d6}.nav-li .nav-li-list{z-index:10;background-color:#fff;display:none;width:128px;position:absolute;top:50px;box-shadow:0 2px 3px #ccc;overflow:hidden}.nav-li-list:hover,.nav-li:hover .nav-li-list,.nav-li>a:hover .nav-li-list{display:block}.nav-li-list>a{display:block;color:#000;width:118px;height:34px;margin:10px auto 0 10px;padding-top:5px;font-size:14px;transition:.3s}.nav-li-list>a:hover{color:#ffa5c7;border-right:2px solid #00a1d6}.nav-li.now{border-bottom:2px solid #00a1d6}.main-header-image{width:100%;height:300px;background:transparent no-repeat fixed center;position:relative}.header-search{width:271px;height:32px;background-color:#e5e9ef;background-color:rgba(0,0,0,.12);border-radius:6px;margin:8px 20px auto 20px}.header-container{width:100%;background-color:#fff;z-index:3}.header-search input{float:left;width:190px;height:35px;line-height:35px;border:1px solid #00a1d6;box-shadow:0 0 4px rgba(0,0,0,.05) inset;border-right:0;margin:0;padding:0 10px 0 30px;border-radius:8px 0 0 8px;box-sizing:border-box;color:#999;font-size:12px}.btn:hover{background-color:#bbb}.btn{height:28px;line-height:28px;padding:0 12px;border-radius:1px 0 0 1px;color:#333;border-color:#bbb}.btn.active{border:0;background-color:#288ecf;color:#fff}.header-search .btn-search{border-radius:0 8px 8px 0;width:80px;height:35px;margin:0;padding-left:10px;border:1px solid #00a1d6;background-color:#00a1d6;color:#fff;font-size:16px;cursor:pointer;overflow:hidden}.btn-search:hover{background-color:#76c4d2;border-color:#76c4d2}.unslider-banner{width:450px;overflow:hidden}.index-banner{margin-top:20px;width:430px;height:215px}.block-banner{float:left;overflow:hidden;border-radius:12px}.block-banner img{height:100%}.block-banner>ul{height:100%;width:500%;position:absolute;left:0}.block-banner>.info-bottom{height:34px;line-height:40px;padding:0 80px 0 11px;cursor:auto;position:absolute;bottom:0;left:0;background:rgba(0,0,0,.45);background:-webkit-linear-gradient(bottom,rgba(0,0,0,.7) 0,rgba(0,0,0,0) 100%);background:-moz-linear-gradient(bottom,rgba(0,0,0,.7) 0,rgba(0,0,0,0) 100%);background:-ms-linear-gradient(bottom,rgba(0,0,0,.7) 0,rgba(0,0,0,0) 100%);background:-o-linear-gradient(bottom,rgba(0,0,0,.7) 0,rgba(0,0,0,0) 100%);background:linear-gradient(bottom,rgba(0,0,0,.7) 0,rgba(0,0,0,0) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000, endColorstr=#66000000);width:100%;color:#fff;text-shadow:1px 1px 2px rgba(0,0,0,.6)}.unslider .unslider-nav{display:block;position:absolute;right:18px;bottom:6px;height:14px}.unslider .unslider-nav li{display:block;cursor:pointer;margin:0 4px;width:10px;height:10px;border-radius:5px;background-color:#00a1d6;float:left;line-height:0;font-size:0}#index-head-area .left-block{width:450px;margin:0 auto;height:300px}#index-head-area .right-block{width:530px}.right-block>.video-block-mask{margin:14px 8px}.sort-left>.banner{height:28px;line-height:28px;border-bottom:1px solid #ddd}.banner>p{font-size:20px;color:#333;height:25px;width:auto;line-height:20px;padding:0;overflow:hidden}.area-inner>.sort-left{width:700px}.area-inner>.sort-right{margin-left:30px;width:250px}.area-inner>.sort-right>.banner{border-bottom:1px solid #e84c3d}.sort-tool-box{width:360px;margin:12px 0 0 0}.sort-tool-box>.btn{margin:5px 15px 5px 0;cursor:pointer}.list-sort-block{margin-top:10px;border-top:1px solid #e5e9ef}.video-item{border-right:1px solid #e5e9ef;border-bottom:1px solid #e5e9ef}.video-block-small{width:330px;height:94px;margin:10px 9px 40px 9px;overflow:hidden}.video-block-small>.left{width:150px}.video-block-small>.right{width:180px;padding-left:10px}.video-block-small .thumb{width:150px;height:94px;overflow:hidden}.video-block-small .thumb>img{margin:0 12px 0 0;height:100%}.video-block-small .info{position:absolute;height:22px;line-height:26px;padding:0 3px;color:#ccc;bottom:0;left:0;width:150px;top:auto;background-color:transparent;background-color:rgba(0,0,0,.45);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#66000000, endColorstr=#66000000)}.info>.info-text{color:#ccc;font-size:11px}.video-block-small .title{font-size:14px;line-height:16px;height:32px;width:170px;margin:0;color:#333;overflow:hidden;word-break:break-all;-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease}.video-block-small .title:hover{color:#e04270}.up{display:block;height:16px;overflow:hidden;margin:8px 0;color:#ff9101}.up:hover{color:#e84c3d}.video-block-small .desc{color:#999;display:inline-block;overflow:hidden;line-height:16px;height:16px}.side-video-list{width:100%;margin-top:20px}.side-video-item{height:65px;margin:0 0 12px;border-bottom:1px solid #eee;padding:0 4px;position:relative}.side-video-item>.left{display:block;width:74px}.side-video-item>.left>img{width:74px;height:41px}.side-video-item>.right{width:150px;margin:0 auto 0 10px}.side-video-item .title{display:block;width:150px;font-size:12px;height:16px;line-height:16px;overflow:hidden;-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease;color:#888}.side-video-item .title:hover{color:#e04270}#footer{margin-top:50px;width:100%;height:230px;background-color:#eee}.about-block{margin-top:40px;overflow:hidden}.about-item{width:320px;height:150px;padding-left:20px}.about-item.left{border-right:1px solid #cfd3d8}.about-item.right{border-left:1px solid #cfd3d8}.about-title{text-align:left;list-style:none;line-height:22px;font-size:14px;color:#7e858c}.about-links>a{margin:3px 0;display:block;color:#222;line-height:22px;font-size:13px}.about-links>a:hover{color:#00a1d6}.about-links{margin-top:20px}.area-player{margin-top:30px;margin-bottom:30px}.video-info{width:100%;padding:0 0 10px 0;background-color:#FFF;border-bottom:1px solid #dadde3}.video-info .left{padding:5px 0 8px 0;width:640px;overflow:hidden}.video-info .right{width:240px;overflow:hidden}.video-info .title>h1{display:block;color:#525659;overflow:hidden;line-height:24px;width:100%;text-overflow:ellipsis;font-weight:400;white-space:nowrap;padding:8px 0;font-size:20px}.video-info .info{width:400px;margin:10px auto}.video-info .play-info>.info-text{color:#99a2aa;font-size:11px;margin-right:20px}.video-info .info>.info-text{color:#99a2aa;font-size:13px}.video-info .up-face{margin:15px 15px 0 0}.video-info .up-face>a>img{display:block;height:64px;width:64px;border-radius:64px;margin:0 auto;border:2px solid transparent;position:relative;z-index:1}.video-info .up-info{margin:15px auto 10px 20px}.up-info>.title{max-width:120px;font-size:14px;word-wrap:break-word;overflow:hidden;word-break:break-all;text-overflow:ellipsis;height:20px;white-space:nowrap}.up-info>.brief{width:140px;color:#333;line-height:20px;min-height:11px;overflow:hidden;word-wrap:break-word}.video-brief{padding:30px 0;border-top:1px solid #dadde3;border-bottom:1px solid #dadde3}.video-brief .desc{max-height:120px;overflow:hidden;white-space:pre-wrap}.video-brief .tags{width:100%;margin:20px 0 30px 0;border-bottom:1px solid #dadde3}.video-brief .tags>li{list-style-type:none;margin:0 10px 8px 0;border:1px solid #00a1d6;border-radius:20px;padding:0 10px;position:relative;height:22px}.label{display:inline-block;font-size:18px;line-height:24px}.comments{margin-top:30px}.video-part-select{margin-bottom:8px;overflow:hidden}.video-part-select>span.active{color:#fff;background-color:#00a1d6;border-color:#00a1d6;cursor:not-allowed}.video-part-select>span{display:block;color:#222;border-radius:4px;border:1px solid #ccd0d7;overflow:hidden;padding:3px 7px 3px 7px;margin:0 20px 12px 0;background:#fff;height:23px;line-height:17px;min-width:117px;text-overflow:ellipsis;white-space:nowrap;transition:.15s;transition-property:background-color,border-color,color;cursor:pointer}.video-part-select>span:hover{color:#fff;background-color:#00a1d6}.search-info{padding-top:30px;padding-bottom:30px;background-color:#fff;border-bottom:1px solid #dadde3}.search-block{height:42px;width:430px}.search-block>.input-wrap{height:100%;position:relative;width:330px;border-radius:4px;margin-right:10px}.input-wrap>input{width:300px;height:100%;box-shadow:none;margin-left:20px;padding:10px 15px;background:0 0;border:2px solid #ccd0d7;border-radius:4px}.search-block>.search-btn{cursor:pointer;float:left;width:90px;color:#fff;background:#00a1d6;border-radius:4px;font-size:16px;letter-spacing:2px;line-height:42px;text-align:center}.search-select-block{margin:20px auto;width:316px;height:100%;border-bottom:1px solid #ccd0d7}.search-select-block>.wrap{display:block}.search-select-block>.wrap>.sub{list-style-type:none;width:39px;height:100%;line-height:54px;font-size:16px;color:#222;margin:0 20px;text-align:center;cursor:pointer}.search-select-block>.wrap>.sub.active{border-bottom:2px solid #00a1d6}.search-select-block>.wrap>.sub:hover{color:#00a1d6}.search-fliter-block{margin:20px auto;width:980px;border-bottom:1px solid #ccd0d7}.search-fliter-block>.wrap{display:block;margin:20px auto}.search-fliter-block>.wrap .sub{list-style-type:none;padding-left:8px;padding-right:8px;border-radius:4px;margin-right:16px;font-size:14px;color:#222;text-decoration:none;cursor:pointer;line-height:24px}.search-fliter-block>.wrap>.sub:hover{color:#00a1d6}.search-fliter-block>.wrap>.sub.active{color:#fff;background-color:#00a1d6}.search-result-content{margin:20px auto;width:980px}.special-li{width:100%;height:110px;padding:20px 0;position:relative;border-bottom:1px solid #e5e9ef}.special-li>.img{height:70px;width:70px;border-radius:4px;overflow:hidden}.special-li img{width:100%;min-height:100%}.special-li>.info{padding-left:20px;width:800px;height:70px}.special-li>.info>.title{font-size:16px;line-height:16px;color:#222;-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease}.special-li>.info>.title:hover{color:#e04270}.special-li>.info>.desc{margin-top:12px;color:#99a2aa;font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.special-li>.info>.info{margin-top:5px}.special-li>.info .info-text{color:#879098;font-size:12px;margin-right:20px}.search-video-block{height:208px;width:168px;border:1px solid #e5e9ef;border-radius:4px;float:left;margin:20px 13px 0 13px}.search-video-block .img{height:100px;border-radius:4px;overflow:hidden;position:relative}.search-video-block .img>img{width:100%;min-height:100%}.search-video-block .img>.time{position:absolute;right:0;bottom:0;line-height:18px;padding:0 5px;color:#fff;background-color:#333;background-color:rgba(0,0,0,.5);border-top-left-radius:4px}.search-video-block .other-info{width:166px;text-align:center;margin:10px auto;overflow:hidden}.search-video-block .other-info>.title{display:block;font-size:13px;line-height:20px;height:35px;overflow:hidden;color:#222;-webkit-transition:color .2s ease;-moz-transition:color .2s ease;-ms-transition:color .2s ease;-o-transition:color .2s ease;transition:color .2s ease}.search-video-block .other-info>.title:hover{color:#00a1d6}.search-video-block .other-info .info{margin:10px 5px}.search-video-block .other-info .info-text{color:#879098;font-size:12px;margin-right:20px}.area-pager{overflow:hidden;margin:4px auto;padding:4px 0;height:auto}.area-pager>span{display:block;margin:0 4px 0 0;padding:0 4px;min-width:32px;width:auto;height:32px;border:none;border-radius:1px;background-color:#3a9bd9;box-shadow:0 1px 1px rgba(0,0,0,.1);color:#fff;text-align:center;text-shadow:0 1px 1px rgba(0,0,0,.1);font-weight:700;font-size:12px;line-height:32px;cursor:pointer}.area-pager>span:hover{background-color:#eee;box-shadow:inset 0 1px 2px rgba(0,0,0,.2);color:#333}.area-pager>span.active{background-color:#eee;box-shadow:inset 0 1px 2px rgba(0,0,0,.2);color:#333}.area-pager>span.active:hover{cursor:not-allowed}.search-pager{margin:30px auto 20px 20px}.hidden{display:none}@-webkit-keyframes scale{0%{-webkit-transform:scale(1);transform:scale(1);opacity:1}45%{-webkit-transform:scale(.1);transform:scale(.1);opacity:.7}80%{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@keyframes scale{0%{-webkit-transform:scale(1);transform:scale(1);opacity:1}45%{-webkit-transform:scale(.1);transform:scale(.1);opacity:.7}80%{-webkit-transform:scale(1);transform:scale(1);opacity:1}}@-webkit-keyframes rotate_pacman_half_up{0%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}50%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}100%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@keyframes rotate_pacman_half_up{0%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}50%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}100%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}}@-webkit-keyframes rotate_pacman_half_down{0%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}50%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}@keyframes rotate_pacman_half_down{0%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}50%{-webkit-transform:rotate(0);transform:rotate(0)}100%{-webkit-transform:rotate(90deg);transform:rotate(90deg)}}@-webkit-keyframes pacman-balls{75%{opacity:.7}100%{-webkit-transform:translate(-100px,-6.25px);transform:translate(-100px,-6.25px)}}@keyframes pacman-balls{75%{opacity:.7}100%{-webkit-transform:translate(-100px,-6.25px);transform:translate(-100px,-6.25px)}}.pacman{position:relative}.pacman>div:nth-child(2){-webkit-animation:pacman-balls 1s 0s infinite linear;animation:pacman-balls 1s 0s infinite linear}.pacman>div:nth-child(3){-webkit-animation:pacman-balls 1s .33s infinite linear;animation:pacman-balls 1s .33s infinite linear}.pacman>div:nth-child(4){-webkit-animation:pacman-balls 1s .66s infinite linear;animation:pacman-balls 1s .66s infinite linear}.pacman>div:nth-child(5){-webkit-animation:pacman-balls 1s .99s infinite linear;animation:pacman-balls 1s .99s infinite linear}.pacman>div:first-of-type{width:0;height:0;border-right:25px solid transparent;border-top:25px solid #ffa5c7;border-left:25px solid #ffa5c7;border-bottom:25px solid #ffa5c7;border-radius:25px;-webkit-animation:rotate_pacman_half_up .5s 0s infinite;animation:rotate_pacman_half_up .5s 0s infinite}.pacman>div:nth-child(2){width:0;height:0;border-right:25px solid transparent;border-top:25px solid #ffa5c7;border-left:25px solid #ffa5c7;border-bottom:25px solid #ffa5c7;border-radius:25px;-webkit-animation:rotate_pacman_half_down .5s 0s infinite;animation:rotate_pacman_half_down .5s 0s infinite;margin-top:-50px}.pacman>div:nth-child(3),.pacman>div:nth-child(4),.pacman>div:nth-child(5),.pacman>div:nth-child(6){background-color:#ffa5c7;width:15px;height:15px;border-radius:100%;margin:2px;position:absolute;-webkit-transform:translate(0,-6.25px);-ms-transform:translate(0,-6.25px);transform:translate(0,-6.25px);top:25px;left:100px}.loading-pacman-block{width:150px;height:70px;padding-top:10px;margin:100px auto}.loading-content{width:100%;height:300px}.video-js .vjs-danmu{overflow:hidden;position:absolute;top:0;left:0;bottom:0;right:0;pointer-events:none;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.video-js .vjs-danmu .cmt{white-space:nowrap;padding:3px 0 0 0;margin:0;line-height:100%;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;text-decoration:none;letter-spacing:0;position:absolute;word-break:keep-all;text-wrap:none;border:0!important;-webkit-text-size-adjust:none;text-size-adjust:none}.video-js .vjs-danmu .cmt.noshadow{text-shadow:none!important}.video-js .vjs-danmu .cmt.rshadow{text-shadow:-1px 0 #fff,0 1px #fff,1px 0 #fff,0 -1px #fff!important}.vjs-danmu-control .vjs-menu-icon:before{content:'\f110';font-family:VideoJS;font-weight:400;font-style:normal;font-size:1.8em;line-height:1.67em}.vjs-danmu-control .vjs-danmu-switch{font-size:1em;line-height:3em;position:absolute;top:0;left:0;width:100%;height:100%;text-align:center;box-sizing:inherit}.cmt{will-change:transform}@keyframes cmt-move-left{from{transform:translateX(100%)}}@keyframes cmt-move-right{to{transform:translateX(-100%)}}
--------------------------------------------------------------------------------
/docs/css/slider.css:
--------------------------------------------------------------------------------
1 | .unslider{overflow:auto;margin:0;padding:0}.unslider-wrap{position:relative}.unslider-wrap.unslider-carousel>li{float:left}.unslider-vertical>ul{height:100%}.unslider-vertical li{float:none;width:100%}.unslider-fade{position:relative}.unslider-fade .unslider-wrap li{position:absolute;left:0;top:0;right:0;z-index:8}.unslider-fade .unslider-wrap li.unslider-active{z-index:10}.unslider li,.unslider ol,.unslider ul{list-style:none;margin:0;padding:0;border:none}.unslider-arrow{position:absolute;left:20px;z-index:2;cursor:pointer}.unslider-arrow.next{left:auto;right:20px}
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/docs/favicon.ico
--------------------------------------------------------------------------------
/docs/img/bg0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/docs/img/bg0.png
--------------------------------------------------------------------------------
/docs/img/bg1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/docs/img/bg1.jpg
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BH-5
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
122 |
123 |
124 |
127 |
128 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
178 |
179 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/docs/js/slider.min.js:
--------------------------------------------------------------------------------
1 | !function(t){return t?(t.Unslider=function(n,e){var i=this;return i._="unslider",i.defaults={autoplay:!1,delay:3e3,speed:750,easing:"swing",keys:{prev:37,next:39},nav:!0,arrows:{prev:'Prev',next:'Next'},animation:"horizontal",selectors:{container:"ul:first",slides:"li"},animateHeight:!1,activeClass:i._+"-active",swipe:!0,swipeThreshold:.2},i.$context=n,i.options={},i.$parent=null,i.$container=null,i.$slides=null,i.$nav=null,i.$arrows=[],i.total=0,i.current=0,i.prefix=i._+"-",i.eventSuffix="."+i.prefix+~~(2e3*Math.random()),i.interval=null,i.init=function(n){return i.options=t.extend({},i.defaults,n),i.$container=i.$context.find(i.options.selectors.container).addClass(i.prefix+"wrap"),i.$slides=i.$container.children(i.options.selectors.slides),i.setup(),t.each(["nav","arrows","keys","infinite"],function(n,e){i.options[e]&&i["init"+t._ucfirst(e)]()}),jQuery.event.special.swipe&&i.options.swipe&&i.initSwipe(),i.options.autoplay&&i.start(),i.calculateSlides(),i.$context.trigger(i._+".ready"),i.animate(i.options.index||i.current,"init")},i.setup=function(){i.$context.addClass(i.prefix+i.options.animation).wrap(''),i.$parent=i.$context.parent("."+i._);var t=i.$context.css("position");"static"===t&&i.$context.css("position","relative"),i.$context.css("overflow","hidden")},i.calculateSlides=function(){if(i.total=i.$slides.length,"fade"!==i.options.animation){var t="width";"vertical"===i.options.animation&&(t="height"),i.$container.css(t,100*i.total+"%").addClass(i.prefix+"carousel"),i.$slides.css(t,100/i.total+"%")}},i.start=function(){return i.interval=setTimeout(function(){i.next()},i.options.delay),i},i.stop=function(){return clearTimeout(i.interval),i},i.initNav=function(){var n=t('');i.$slides.each(function(e){var o=this.getAttribute("data-nav")||e+1;t.isFunction(i.options.nav)&&(o=i.options.nav.call(i.$slides.eq(e),e,o)),n.children("ol").append(''+o+"")}),i.$nav=n.insertAfter(i.$context),i.$nav.find("li").on("click"+i.eventSuffix,function(){var n=t(this).addClass(i.options.activeClass);n.siblings().removeClass(i.options.activeClass),i.animate(n.attr("data-slide"))})},i.initArrows=function(){i.options.arrows===!0&&(i.options.arrows=i.defaults.arrows),t.each(i.options.arrows,function(n,e){i.$arrows.push(t(e).insertAfter(i.$context).on("click"+i.eventSuffix,i[n]))})},i.initKeys=function(){i.options.keys===!0&&(i.options.keys=i.defaults.keys),t(document).on("keyup"+i.eventSuffix,function(n){t.each(i.options.keys,function(e,o){n.which===o&&t.isFunction(i[e])&&i[e].call(i)})})},i.initSwipe=function(){var t=i.$slides.width();"fade"!==i.options.animation&&i.$container.on({movestart:function(t){return t.distX>t.distY&&t.distX<-t.distY||t.distX-t.distY?!!t.preventDefault():void i.$container.css("position","relative")},move:function(n){i.$container.css("left",-(100*i.current)+100*n.distX/t+"%")},moveend:function(n){Math.abs(n.distX)/t>i.options.swipeThreshold?i[n.distX<0?"next":"prev"]():i.$container.animate({left:-(100*i.current)+"%"},i.options.speed/2)}})},i.initInfinite=function(){var n=["first","last"];t.each(n,function(t,e){i.$slides.push.apply(i.$slides,i.$slides.filter(':not(".'+i._+'-clone")')[e]().clone().addClass(i._+"-clone")["insert"+(0===t?"After":"Before")](i.$slides[n[~~!t]]()))})},i.destroyArrows=function(){t.each(i.$arrows,function(t,n){n.remove()})},i.destroySwipe=function(){i.$container.off("movestart move moveend")},i.destroyKeys=function(){t(document).off("keyup"+i.eventSuffix)},i.setIndex=function(t){return 0>t&&(t=i.total-1),i.current=Math.min(Math.max(0,t),i.total-1),i.options.nav&&i.$nav.find('[data-slide="'+i.current+'"]')._active(i.options.activeClass),i.$slides.eq(i.current)._active(i.options.activeClass),i},i.animate=function(n,e){if("first"===n&&(n=0),"last"===n&&(n=i.total),isNaN(n))return i;i.options.autoplay&&i.stop().start(),i.setIndex(n),i.$context.trigger(i._+".change",[n,i.$slides.eq(n)]);var o="animate"+t._ucfirst(i.options.animation);return t.isFunction(i[o])&&i[o](i.current,e),i},i.next=function(){var t=i.current+1;return t>=i.total&&(t=0),i.animate(t,"next")},i.prev=function(){return i.animate(i.current-1,"prev")},i.animateHorizontal=function(t){var n="left";return"rtl"===i.$context.attr("dir")&&(n="right"),i.options.infinite&&i.$container.css("margin-"+n,"-100%"),i.slide(n,t)},i.animateVertical=function(t){return i.options.animateHeight=!0,i.options.infinite&&i.$container.css("margin-top",-i.$slides.outerHeight()),i.slide("top",t)},i.slide=function(t,n){if(i.options.animateHeight&&i._move(i.$context,{height:i.$slides.eq(n).outerHeight()},!1),i.options.infinite){var e;n===i.total-1&&(e=i.total-3,n=-1),n===i.total-2&&(e=0,n=i.total-2),"number"==typeof e&&(i.setIndex(e),i.$context.on(i._+".moved",function(){i.current===e&&i.$container.css(t,-(100*e)+"%").off(i._+".moved")}))}var o={};return o[t]=-(100*n)+"%",i._move(i.$container,o)},i.animateFade=function(t){var n=i.$slides.eq(t).addClass(i.options.activeClass);i._move(n.siblings().removeClass(i.options.activeClass),{opacity:0}),i._move(n,{opacity:1},!1)},i._move=function(t,n,e,o){return e!==!1&&(e=function(){i.$context.trigger(i._+".moved")}),t._move(n,o||i.options.speed,i.options.easing,e)},i.init(e)},t.fn._active=function(t){return this.addClass(t).siblings().removeClass(t)},t._ucfirst=function(t){return(t+"").toLowerCase().replace(/^./,function(t){return t.toUpperCase()})},t.fn._move=function(){return this.stop(!0,!0),t.fn[t.fn.velocity?"velocity":"animate"].apply(this,arguments)},void(t.fn.unslider=function(n){return this.each(function(){var e=t(this);if("string"==typeof n&&e.data("unslider")){n=n.split(":");var i=e.data("unslider")[n[0]];if(t.isFunction(i))return i.apply(e,n[1]?n[1].split(","):null)}return e.data("unslider",new t.Unslider(e,n))})})):console.warn("Unslider needs jQuery")}(window.jQuery);
--------------------------------------------------------------------------------
/docs/js/stickup.min.js:
--------------------------------------------------------------------------------
1 | jQuery(function(t){"use strict";var e=function(){},o={},n=0;e.prototype={dataProperty:"data-menu",itemClass:"",itemHover:"",marginTop:0,beforeStick:null,afterStick:null,beforeUnstick:null,afterUnstick:null,region:"top",_selector:"",_jqDom:null,_menuItems:[],_height:0,_parentMarginTop:0,_top:0,_marginBottom:0,onScroll:function(e,o){var n=null,r=null,i=this;if(i._menuItems&&i._menuItems.length>0)for(var a=null,s=0,m=null,l=0;ls-50&&s+50>o&&(i._jqDom.find("."+i.itemClass).removeClass(i.itemHover),i._jqDom.find("."+i.itemClass+":eq("+l+")").addClass(i.itemHover)),"up"==e&&(n=.4*m.height(),r=s-n,o>r?(i._jqDom.find("."+i.itemClass).removeClass(i.itemHover),i._jqDom.find("."+i.itemClass+":eq("+l+")").addClass(i.itemHover)):50>o&&(i._jqDom.find("."+i.itemClass).removeClass(i.itemHover),i._jqDom.find("."+i.itemClass+":eq(0)").addClass(i.itemHover)));i._top0?a.marginTop=parseInt(r.topMargin.replace("px","")):isNaN(parseInt(r.topMargin))?(console.log("incorrect argument, ignored."),a.marginTop=0):a.marginTop=parseInt(r.topMargin):a.marginTop=0,a.itemClass=r.itemClass,a.itemHover=r.itemHover):console.log("warm:needs arguments"),a.dataProperty=r.dataProperty||a.dataProperty,a.region=r.region||a.region,a._height=parseInt(a._jqDom.height()),a._marginBottom=parseInt(a._jqDom.css("margin-bottom")),a._parentMarginTop=parseInt(a._jqDom.next().closest("div").css("margin-top")),a._top=parseInt(a._jqDom.offset().top),o[a._selector]=a},t.fn.stickUp=function(t){o[this.selector]||e._init_(this,t)},t(document).on("scroll",function(){var e=parseInt(t(document).scrollTop()),r=e>n?"down":"up";for(var i in o)o[i].onScroll(r,e);n=e})});
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/favicon.ico
--------------------------------------------------------------------------------
/gulpfile.babel.js:
--------------------------------------------------------------------------------
1 | import gulp from 'gulp';
2 | import browserify from 'browserify';
3 | import source from 'vinyl-source-stream';
4 | import buffer from 'vinyl-buffer';
5 | import babelify from 'babelify';
6 | import uglify from 'gulp-uglify';
7 | import rimraf from 'rimraf';
8 | import sourcemaps from 'gulp-sourcemaps';
9 | import cleancss from 'gulp-clean-css';
10 | import imagemin from 'gulp-imagemin';
11 | import pngquant from 'imagemin-pngquant';
12 | import runSequence from 'run-sequence';
13 | import ghPages from 'gulp-gh-pages';
14 | import concatCss from 'gulp-concat-css';
15 |
16 | const paths = {
17 | bundle: 'app.js',
18 | entry: 'src/js/Index.js',
19 | srcCss: 'src/styles/*.css',
20 | srcImg: 'src/images/**',
21 | srcLint: ['src/**/*.js', 'test/**/*.js'],
22 | distCss: 'dist/css',
23 | distJs: 'dist/js',
24 | distImg: 'dist/img'
25 | };
26 |
27 |
28 | gulp.task('clean', cb => {
29 | rimraf('dist', cb);
30 | });
31 |
32 |
33 | gulp.task('browserify', () => {
34 | browserify(paths.entry, {debug: false})
35 | .transform(babelify)
36 | .bundle()
37 | .pipe(source(paths.bundle))
38 | .pipe(buffer())
39 | .pipe(uglify())
40 | .pipe(gulp.dest(paths.distJs));
41 | });
42 |
43 | gulp.task('browserify_debug', () => {
44 | browserify(paths.entry, {debug: true})
45 | .transform(babelify)
46 | .bundle()
47 | .pipe(source(paths.bundle))
48 | .pipe(buffer())
49 | .pipe(sourcemaps.init({loadMaps: true}))
50 | .pipe(uglify())
51 | .pipe(sourcemaps.write('.'))
52 | .pipe(gulp.dest(paths.distJs));
53 | });
54 |
55 | gulp.task('styles', () => {
56 | gulp.src(paths.srcCss)
57 | .pipe(concatCss("main.css"))
58 | .pipe(cleancss({advanced: false}))
59 | .pipe(gulp.dest(paths.distCss))
60 | });
61 |
62 | gulp.task('images', () => {
63 | gulp.src(paths.srcImg)
64 | .pipe(imagemin({
65 | progressive: true,
66 | svgoPlugins: [{removeViewBox: false}],
67 | use: [pngquant()]
68 | }))
69 | .pipe(gulp.dest(paths.distImg));
70 | });
71 |
72 | gulp.task('watchTask', () => {
73 | gulp.watch(paths.srcCss, ['styles']);
74 | });
75 |
76 |
77 | gulp.task('build', cb => {
78 | process.env.NODE_ENV = 'production';
79 | runSequence('clean', ['browserify', 'styles', 'images', 'copyAssets'], cb);
80 | });
81 |
82 |
83 | gulp.task('source', cb=> {
84 | process.env.NODE_ENV = 'debug';
85 | runSequence('clean', ['browserify_debug', 'styles', 'images', 'copyAssets'], cb);
86 | });
87 |
88 |
89 | gulp.task('copyAssets', ()=> {
90 | gulp.src([
91 | 'assets/js/*'
92 | ]).pipe(buffer())
93 | .pipe(uglify())
94 | .pipe(gulp.dest('dist/js'));
95 |
96 | gulp.src([
97 | 'assets/css/*'
98 | ]).pipe(cleancss({advanced: false}))
99 | .pipe(gulp.dest('dist/css'));
100 |
101 | gulp.src([
102 | 'favicon.ico'
103 | ]).pipe(gulp.dest('dist'));
104 |
105 | gulp.src([
106 | 'src/index.html'
107 | ]).pipe(gulp.dest('dist'));
108 | });
109 |
110 |
111 | gulp.task('deploy', () => {
112 | gulp.src('dist/**/**')
113 | .pipe(ghPages());
114 | });
115 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bilibili-html5",
3 | "version": "2.1.0",
4 | "description": "",
5 | "main": "app.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "https://github.com/WhiteBlue/bilibili-html5"
9 | },
10 | "keywords": [
11 | "gulp",
12 | "react",
13 | "browserify",
14 | "ES6",
15 | "ES2015",
16 | "babel"
17 | ],
18 | "scripts": {
19 | "build":"gulp build"
20 | },
21 | "author": "WhiteBlue",
22 | "license": "MIT",
23 | "homepage": "https://bilibilih5.club",
24 | "dependencies": {
25 | "history": "^1.17.0",
26 | "react": "0.14.8",
27 | "react-dom": "0.14.0",
28 | "react-router": "1.0.3",
29 | "reqwest": "^2.0.5",
30 | "video.js": "^5.11.9"
31 | },
32 | "devDependencies": {
33 | "autoprefixer": "^6.0.0",
34 | "babel": "^6.3.13",
35 | "babel-core": "6.3.17",
36 | "babel-preset-es2015": "^6.3.13",
37 | "babel-preset-react": "^6.3.13",
38 | "babel-register": "^6.6.5",
39 | "babelify": "^7.2.0",
40 | "browserify": "^13.0.0",
41 | "gulp": "^3.9.0",
42 | "gulp-clean-css": "^3.0.4",
43 | "gulp-concat-css": "^2.3.0",
44 | "gulp-gh-pages": "^0.5.4",
45 | "gulp-imagemin": "^2.4.0",
46 | "gulp-rename": "^1.2.2",
47 | "gulp-sourcemaps": "^1.5.2",
48 | "gulp-uglify": "^1.4.0",
49 | "imagemin-pngquant": "^4.2.0",
50 | "lodash": "^4.6.0",
51 | "rimraf": "^2.4.3",
52 | "run-sequence": "^1.1.2",
53 | "tap-nyan": "0.0.2",
54 | "vinyl-buffer": "^1.0.0",
55 | "vinyl-source-stream": "^1.1.0"
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # bilibili-html5
2 |
3 | An unofficial website of [bilibili.com](http://bilibili.com).
4 |
5 |
6 | 
7 |
8 |
9 | ## Features
10 |
11 |
12 | * html5 video player support "Danmu"
13 | * video part/quality select
14 |
15 | ## Build
16 |
17 |
18 | ```
19 | npm install
20 |
21 | npm run build
22 |
23 | ```
24 |
25 | ## Others
26 |
27 | * Video player
28 | * video.js - [https://github.com/videojs/video.js](https://github.com/videojs/video.js)
29 | * Danmaku support
30 | * edited from CommentCoreLibrary - [https://github.com/jabbany/CommentCoreLibrary](https://github.com/jabbany/CommentCoreLibrary)
31 |
32 | ## License
33 |
34 | MIT License
35 |
36 | Copyright (c) 2016 Castaway Consulting LLC
37 |
38 | Permission is hereby granted, free of charge, to any person obtaining a copy
39 | of this software and associated documentation files (the "Software"), to deal
40 | in the Software without restriction, including without limitation the rights
41 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
42 | copies of the Software, and to permit persons to whom the Software is
43 | furnished to do so, subject to the following conditions:
44 |
45 | The above copyright notice and this permission notice shall be included in all
46 | copies or substantial portions of the Software.
47 |
48 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
49 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
50 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
51 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
52 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
53 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
54 | SOFTWARE.
55 |
--------------------------------------------------------------------------------
/src/images/bg0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/src/images/bg0.png
--------------------------------------------------------------------------------
/src/images/bg1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WhiteBlue/bilibili-html5/701a5d991400c23739a5a5f811111c2f4bf60bb8/src/images/bg1.jpg
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BH-5
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
122 |
123 |
124 |
127 |
128 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
178 |
179 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/src/js/App.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var IndexPage = require("./page/IndexPage");
4 |
5 | var IndexContent = React.createClass({
6 | componentDidMount(){
7 | document.title = "BH5 | 首页";
8 | },
9 | render: function () {
10 | return
11 |
12 |
;
13 | }
14 | }
15 | );
16 |
17 |
18 | module.exports = React.createClass({
19 | render(){
20 | return {this.props.children || }
;
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/src/js/Config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | // base_url: "http://localhost:8080/",
3 | base_url: "http://123.206.255.148",
4 | routes: {
5 | INDEX_RANK: "top/",
6 | TOP_RANK: "toprank",
7 | BANNER: "banner",
8 | VIDEO_INFO: "view/",
9 | VIDEO_URL: "video/",
10 | SORT_VIDEOS: "sort/",
11 | BANGUMI_INFO: "bangumiinfo/",
12 | BANGUMI_INDEX: "bangumiindex",
13 | BANGUMI_LIST: "bangumi",
14 | SEARCH: "search",
15 | SEARCH_BY_TYPE: "searchbytype",
16 | GET_COMMENT: "http://comment.bilibili.cn/"
17 | },
18 | index_sorts: [24, 33, 31, 20, 17, 36, 119],
19 |
20 | sort_tags: {
21 | 1: "动画",
22 | 24: "MAD·AMV",
23 | 25: "MMD·3D",
24 | 47: "短片·手书·配音",
25 | 27: "综合",
26 |
27 |
28 | 13: "番剧",
29 | 33: "连载动画",
30 | 32: "完结动画",
31 | 152: "官方延伸",
32 | 153: "国产动画",
33 |
34 |
35 | 3: "音乐",
36 | 31: "翻唱",
37 | 30: "VOCALOID·UTAU",
38 | 29: "三次元音乐",
39 | 28: "同人音乐",
40 | 54: "OP/ED/OST",
41 | 130: "音乐选集",
42 |
43 |
44 | 129: "舞蹈",
45 | 20: "宅舞",
46 | 154: "三次元舞蹈",
47 | 156: "舞蹈教程",
48 |
49 |
50 | 17: "单机联机",
51 | 65: "网游·电竞",
52 | 136: "音游",
53 | 19: "Mugen",
54 | 121: "GMV",
55 |
56 |
57 | 36: "科技",
58 | 37: "纪录片",
59 | 124: "趣味科普人文",
60 | 122: "野生技术协会",
61 | 39: "演讲·公开课",
62 | 95: "数码",
63 | 98: "机械",
64 |
65 |
66 | 163: "搞笑",
67 | 138: "生活",
68 | 75: "动物圈",
69 | 76: "美食圈",
70 | 71: "综艺",
71 | 137: "娱乐圈",
72 | 131: "Korea相关",
73 |
74 |
75 | 119: "鬼畜",
76 | 22: "鬼畜调教",
77 | 126: "人力VOCALOID",
78 | 26: "音MAD",
79 | 127: "教程演示"
80 | }
81 | };
82 |
--------------------------------------------------------------------------------
/src/js/Index.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | import {Router, Route} from 'react-router';
3 | var render = require('react-dom').render;
4 |
5 | var App = require('./App');
6 | var ViewPage = require('./page/ViewPage');
7 | var SortPage = require('./page/SortPage');
8 | var SearchPage = require('./page/SearchPage');
9 | var BangumiInfoPage = require('./page/BangumiInfoPage');
10 | var BangumiIndexPage = require('./page/BangumiIndexPage');
11 |
12 |
13 |
14 | render(
15 | (
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ), document.getElementById('root')
24 | );
25 |
--------------------------------------------------------------------------------
/src/js/components/AllRank.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Config = require('../Config');
3 | var reqwest = require('reqwest');
4 |
5 | const VideoItem = React.createClass({
6 | getDefaultProps(){
7 | return {
8 | data: {
9 | title: "",
10 | cover: "",
11 | param: "",
12 | name: "",
13 | play: "",
14 | reply: "",
15 | danmaku: "",
16 | favourite: ""
17 | }
18 | };
19 | },
20 | getInitialState(){
21 | return {
22 | hrefStr: "#/view/"
23 | };
24 | },
25 | render() {
26 | var linkUrl = this.state.hrefStr + this.props.data.param;
27 | return
28 |
29 |
30 |
31 |
弹幕: {this.props.data.danmaku}
32 |
{this.props.data.title}
33 |
34 |
35 | 播放: {this.props.data.play}
36 |
37 |
38 | 回复: {this.props.data.reply}
39 |
40 |
41 |
;
42 | }
43 | });
44 |
45 |
46 | const VideoBlock = React.createClass({
47 | _loadData(tid){
48 | var _this = this;
49 |
50 | var labelName = Config.sort_tags[tid];
51 |
52 | reqwest({
53 | url: Config.base_url + Config.routes.INDEX_RANK + tid
54 | , type: 'json'
55 | , method: 'get'
56 | , crossOrigin: true
57 | , error: function (err) {
58 | console.log('error');
59 | }
60 | , success: function (resp) {
61 | _this.setState({
62 | videoList: resp.videos,
63 | labelName: labelName
64 | });
65 | }
66 | });
67 | },
68 | getInitialState(){
69 | return {
70 | videoList: [],
71 | labelName: ''
72 | };
73 | },
74 | componentDidMount(){
75 | this._loadData(this.props.tid);
76 | },
77 | render(){
78 | var renderVideos = [];
79 | for (var i in this.state.videoList) {
80 | renderVideos.push();
81 | if (i == 9) {
82 | break;
83 | }
84 | }
85 | return
86 |
87 |
95 |
96 | {renderVideos}
97 |
98 |
99 |
100 |
;
101 | }
102 | });
103 |
104 | module.exports = React.createClass({
105 | render(){
106 | var renderList = [];
107 | for (var i in Config.index_sorts) {
108 | var id = Config.index_sorts[i];
109 | renderList.push()
110 | }
111 | return {renderList}
;
112 | }
113 | });
114 |
--------------------------------------------------------------------------------
/src/js/components/BangumiIndex.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Config = require('../Config');
3 | var reqwest = require('reqwest');
4 |
5 | var Loading = require('./Loading');
6 |
7 | const BangumiBanner = React.createClass({
8 | _loadBanner(){
9 | $('.block-banner').unslider({
10 | animation: 'horizontal',
11 | autoplay: true,
12 | arrows: false,
13 | keys: false
14 | });
15 | },
16 | getDefaultProps(){
17 | return {
18 | list: []
19 | }
20 | },
21 | componentDidMount(){
22 | this._loadBanner();
23 | },
24 | render(){
25 | var banners = [];
26 |
27 | for (var i = 0; i < this.props.list.length; i++) {
28 | banners.push(
29 |
30 |
31 |
32 | );
33 | }
34 |
35 | return ;
42 | }
43 | });
44 |
45 | const VideoItem = React.createClass({
46 | getDefaultProps(){
47 | return {
48 | data: {
49 | aid: "",
50 | author: "",
51 | coins: 0,
52 | comment: 0,
53 | create: "",
54 | description: "",
55 | duration: "",
56 | favorites: 0,
57 | mid: 0,
58 | pic: "",
59 | play: 0,
60 | review: 0,
61 | title: "",
62 | typeid: 0,
63 | typename: "",
64 | video_review: 0
65 | }
66 | };
67 | },
68 | getInitialState(){
69 | return {
70 | hrefStr: "#/view/"
71 | };
72 | },
73 | render() {
74 | var linkUrl = this.state.hrefStr + this.props.data.aid;
75 | return ;
93 | }
94 | });
95 |
96 |
97 | module.exports = React.createClass({
98 | _loadData(){
99 | var _this = this;
100 | reqwest({
101 | url: Config.base_url + Config.routes.BANGUMI_INDEX
102 | , type: 'json'
103 | , method: 'get'
104 | , data: {}
105 | , crossOrigin: true
106 | , error: function (err) {
107 | console.log('error:' + err);
108 | }
109 | , success: function (data) {
110 | _this.setState({
111 | indexData: data,
112 | loading: false
113 | });
114 | }
115 | });
116 | },
117 | getInitialState(){
118 | return {
119 | loading: true,
120 | indexData: null
121 | }
122 | },
123 | componentDidMount(){
124 | this._loadData();
125 | },
126 | render(){
127 | var recommend_videos = [];
128 |
129 | if (this.state.indexData != null) {
130 |
131 | for (var i = 0; i < this.state.indexData.recommends.length; i++) {
132 | recommend_videos.push();
133 | }
134 | }
135 |
136 | return
137 |
138 | {
139 | (this.state.loading) ? :
140 | }
141 |
142 |
143 |
144 |
145 |
视频推荐
146 |
147 | {
148 | (this.state.loading) ?
:
149 |
150 | {recommend_videos}
151 |
152 |
153 | }
154 |
155 |
156 |
157 | }
158 | });
159 |
--------------------------------------------------------------------------------
/src/js/components/BangumiInfo.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Config = require('../Config');
3 | var reqwest = require('reqwest');
4 |
5 | var Loading = require('./Loading');
6 |
7 |
8 | var videoHrefStr = "#/view/";
9 | const bangumiHrefStr = "#/bangumi/";
10 |
11 |
12 | const BangumiItem = React.createClass({
13 | getDefaultProps(){
14 | return {
15 | data: {
16 | title: "",
17 | cover: "",
18 | is_finish: "",
19 | season_id: "",
20 | total_count: ""
21 | }
22 | }
23 | },
24 | render(){
25 | return
26 |
27 |

28 |
29 |
30 |
{this.props.data.title}
31 |
32 |
状态: {this.props.data.is_finish == "1" ? "已完结" : "连载中"}
33 |
集数: {this.props.data.total_count}
34 |
35 |
36 |
;
37 | }
38 | });
39 |
40 |
41 | module.exports = React.createClass({
42 | _seasonId: "",
43 | _loadData(){
44 | var _this = this;
45 | reqwest({
46 | url: Config.base_url + Config.routes.BANGUMI_INFO + _this._seasonId
47 | , type: 'json'
48 | , method: 'get'
49 | , data: {}
50 | , crossOrigin: true
51 | , error: function (err) {
52 | console.log('error:' + err);
53 | }
54 | , success: function (data) {
55 | _this.props.cb(data.title);
56 | _this.setState({
57 | bangumiInfo: data,
58 | loading: false
59 | });
60 | }
61 | });
62 | },
63 | getDefaultProps(){
64 | return {
65 | seasonId: 0,
66 | cb: function (content) {
67 | }
68 | }
69 | },
70 | getInitialState(){
71 | return {
72 | loading: true,
73 | bangumiInfo: null
74 | }
75 | },
76 | componentDidMount(){
77 | this._seasonId = this.props.seasonId;
78 | this._loadData();
79 | },
80 | componentWillReceiveProps(nextProps){
81 | this._seasonId = nextProps.seasonId;
82 | this.setState({
83 | loading: true
84 | });
85 | this._loadData();
86 | },
87 | render(){
88 | var seasons = [];
89 | var actors = "";
90 | var videos = [];
91 |
92 | if (this.state.bangumiInfo != null) {
93 | for (var i = 0; i < this.state.bangumiInfo.seasons.length; i++) {
94 | seasons.push();
95 | }
96 |
97 | for (i = 0; i < this.state.bangumiInfo.actor.length; i++) {
98 | actors += this.state.bangumiInfo.actor[i].actor + "、 ";
99 | }
100 |
101 | for (i = 0; i < this.state.bangumiInfo.episodes.length; i++) {
102 | videos.push(
103 |
104 | {this.state.bangumiInfo.episodes[i].index + "." + this.state.bangumiInfo.episodes[i].index_title}
106 | );
107 | }
108 | }
109 |
110 | return
111 | {(this.state.loading) ?
:
112 |
113 |
114 |
{this.state.bangumiInfo.title}
115 |
116 |

117 |
118 |
119 |
声优:{actors}
120 |
121 |
{this.state.bangumiInfo.evaluate}
122 |
123 |
播放数:{this.state.bangumiInfo.play_count} |
124 | 弹幕数:{this.state.bangumiInfo.danmaku_count}
125 |
126 |
127 |
128 | {seasons}
129 |
130 |
131 |
132 |
剧集:
133 |
136 |
137 |
138 |
139 | }
140 |
;
141 | }
142 | });
143 |
--------------------------------------------------------------------------------
/src/js/components/BangumiList.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Config = require('../Config');
3 | var reqwest = require('reqwest');
4 |
5 | var Loading = require('./Loading');
6 |
7 |
8 | const bangumiHrefStr = "#/bangumi/";
9 |
10 | const BangumiItem = React.createClass({
11 | getDefaultProps(){
12 | return {
13 | data: {
14 | title: "",
15 | cover: "",
16 | is_finish: "",
17 | season_id: "",
18 | attention: ""
19 | }
20 | }
21 | },
22 | render(){
23 | return
24 |
25 |
26 |

27 |
28 |
29 |
{this.props.data.title}
30 |
关注: {this.props.data.attention}
31 |
32 |
33 |
34 | ;
35 | }
36 | });
37 |
38 |
39 | module.exports = React.createClass({
40 | _showMore(){
41 | $('.list-bangumi-block').animate({
42 | maxHeight: '2800px'
43 | });
44 | },
45 | _loadData(){
46 | var _this = this;
47 | reqwest({
48 | url: Config.base_url + Config.routes.BANGUMI_LIST
49 | , type: 'json'
50 | , method: 'get'
51 | , data: {}
52 | , crossOrigin: true
53 | , error: function (err) {
54 | console.log('error:' + err);
55 | }
56 | , success: function (data) {
57 | _this.setState({
58 | data: data
59 | });
60 | }
61 | });
62 | },
63 | getInitialState(){
64 | return {
65 | data: null
66 | }
67 | },
68 | componentDidMount(){
69 | this._loadData();
70 | },
71 | render(){
72 | var bangumiList = [];
73 |
74 | if (this.state.data != null) {
75 | for (var i = 0; i < this.state.data.list.length; i++) {
76 | bangumiList.push();
77 | }
78 | }
79 |
80 | return
81 |
82 |
83 |
番剧列表
84 |
85 |
86 |
87 | {bangumiList}
88 |
89 |
90 |
91 |
92 |
95 |
96 |
97 |
;
98 | }
99 | });
100 |
--------------------------------------------------------------------------------
/src/js/components/IndexBanner.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var reqwest = require('reqwest');
3 |
4 | var Config = require('../Config');
5 |
6 |
7 | const Banner = React.createClass({
8 | getDefaultProps(){
9 | return {
10 | bannerList: []
11 | };
12 | },
13 | render(){
14 | var renderBanner = [];
15 | for (var i = 0; i < this.props.bannerList.length; i++) {
16 | var data = this.props.bannerList[i];
17 | renderBanner.push(
18 |
19 | );
20 | }
21 | return ;
29 | }
30 | });
31 |
32 | const BannerBlock = React.createClass({
33 | _loadBanner(){
34 | $('.block-banner').unslider({
35 | animation: 'horizontal',
36 | autoplay: true,
37 | arrows: false,
38 | keys: false
39 | });
40 | },
41 | getDefaultProps(){
42 | return {
43 | bannerList: []
44 | };
45 | },
46 | componentDidMount(){
47 | this._loadBanner();
48 | },
49 | render(){
50 | return ;
51 | }
52 | });
53 |
54 | module.exports = React.createClass({
55 | _loadData(){
56 | var _this = this;
57 | reqwest({
58 | url: Config.base_url + Config.routes.BANNER
59 | , type: 'json'
60 | , method: 'get'
61 | , crossOrigin: true
62 | , error: function (err) {
63 | console.log('error');
64 | }
65 | , success: function (data) {
66 | _this.setState({
67 | banners: data
68 | });
69 | }
70 | });
71 | },
72 | componentDidMount(){
73 | this._loadData();
74 | },
75 | getInitialState(){
76 | return {
77 | banners: []
78 | }
79 | },
80 | render(){
81 | return (this.state.banners.length !== 0) ? : ;
82 | }
83 | });
84 |
--------------------------------------------------------------------------------
/src/js/components/IndexHot.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Config = require('../Config');
3 | var reqwest = require('reqwest');
4 |
5 | const VideoItem = React.createClass({
6 | getDefaultProps(){
7 | return {
8 | data: {
9 | title: "",
10 | cover: "",
11 | param: "",
12 | name: "",
13 | play: "",
14 | reply: "",
15 | danmaku: "",
16 | favourite: ""
17 | }
18 | };
19 | },
20 | getInitialState(){
21 | return {
22 | hrefStr: "#/view/"
23 | };
24 | },
25 | render() {
26 | var linkUrl = this.state.hrefStr + this.props.data.param;
27 | return ;
41 | }
42 | });
43 |
44 | module.exports = React.createClass({
45 | _loadData(){
46 | var _this = this;
47 | reqwest({
48 | url: Config.base_url + Config.routes.TOP_RANK
49 | , type: 'json'
50 | , method: 'get'
51 | , crossOrigin: true
52 | , error: function (err) {
53 | console.log('error');
54 | }
55 | , success: function (data) {
56 | _this.setState({
57 | top: data
58 | });
59 | }
60 | });
61 | },
62 | componentDidMount(){
63 | this._loadData();
64 | },
65 | getInitialState(){
66 | return {
67 | top: []
68 | }
69 | },
70 | render(){
71 | var renderVideos = [];
72 | var count = 0;
73 | for (var i in this.state.top) {
74 | if (count < 6) {
75 | if (i != 'num') {
76 | renderVideos.push();
77 | }
78 | } else {
79 | break;
80 | }
81 | count++;
82 | }
83 | return
84 | {renderVideos}
85 |
86 |
;
87 | }
88 | });
89 |
--------------------------------------------------------------------------------
/src/js/components/Loading.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 |
4 | module.exports = React.createClass({
5 | render(){
6 | return
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
;
17 | }
18 | });
19 |
--------------------------------------------------------------------------------
/src/js/components/Pager.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | _pageChange(page){
5 | if (page < 1) {
6 | page = 1;
7 | }
8 | if (page > this.props.allPage) {
9 | page = this.props.allPage;
10 | }
11 | this.props.pageCallBack(page);
12 | },
13 | getDefaultProps(){
14 | return {
15 | nowPage: 1,
16 | allPage: 0,
17 | showPageCount: 8,
18 | pageCallBack: function (page) {
19 | }
20 | };
21 | },
22 | render(){
23 | var start = this.props.nowPage - this.props.showPageCount / 2;
24 | if (start < 1) {
25 | start = 1;
26 | }
27 | var renderList = [];
28 |
29 | for (var i = 0; i < this.props.showPageCount; i++) {
30 | if (i >= this.props.allPage && this.props.allPage >= 0) {
31 | break;
32 | }
33 | var index = start + i;
34 | if (index === this.props.nowPage) {
35 | renderList.push({index})
36 | } else {
37 | renderList.push({index})
39 | }
40 | }
41 | return (this.props.allPage <= 1 ? :
42 | 首页
43 | 上一页
44 | {renderList}
45 | 下一页
46 |
);
47 | }
48 | });
49 |
--------------------------------------------------------------------------------
/src/js/components/Player.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var reqwest = require('reqwest');
3 |
4 | var Config = require('../Config');
5 | var Loading = require('./Loading');
6 |
7 | var videojs = require("video.js");
8 |
9 | require("../danmaku/VideojsPlugin");
10 | require("../utils/VideojsHotKeys");
11 |
12 | var _oldPlayer = null; //Video.js的dispose()不能放在componentWillUnmount事件之前(和React.js自身清理相冲突)
13 |
14 | const VideoBlock = React.createClass({
15 | _player: null,
16 | _loadVideoJs(commentUrl, videoUrl){
17 | if (_oldPlayer != null) {
18 | _oldPlayer.dispose();
19 | _oldPlayer = null;
20 | }
21 | if (this._player == null) {
22 | this._player = videojs('danmu_player', {
23 | controls: true
24 | }, function () {
25 | this.initDanmaku();
26 | this.hotkeys({
27 | volumeStep: 0.1,
28 | seekStep: 5,
29 | //音量键(M)
30 | enableMute: true,
31 | //滚轮调节音量
32 | enableVolumeScroll: false,
33 | //全屏(F)
34 | enableFullscreen: true,
35 | //数字选择分P
36 | enableNumbers: false,
37 | alwaysCaptureHotkeys: false
38 | });
39 | this.danmu.load(commentUrl);
40 | this.src(videoUrl);
41 | });
42 | } else {
43 | this._player.src(videoUrl);
44 | this._player.danmu.load(commentUrl);
45 | }
46 |
47 | },
48 | getDefaultProps(){
49 | return {
50 | url: "",
51 | pic: "",
52 | commentUrl: ""
53 | };
54 | },
55 | componentDidMount(){
56 | this._loadVideoJs(this.props.commentUrl, this.props.urlList.url);
57 | },
58 | componentWillReceiveProps(nextProps){
59 | if (this._player != null) {
60 | //避免初次加载调用
61 | this._loadVideoJs(nextProps.commentUrl, nextProps.urlList.url);
62 | }
63 | },
64 | componentWillUnmount(){
65 | _oldPlayer = this._player;
66 | this.player = null;
67 | },
68 | render(){
69 | return ;
78 | }
79 | });
80 |
81 |
82 | module.exports = React.createClass({
83 | _cid: null,
84 | _quality: 4,
85 | _selectParts(partStr){
86 | var cid = null;
87 | if (this.props.parts.length !== 0) {
88 | cid = this.props.parts[partStr].cid;
89 | }
90 | this._cid = cid;
91 | this._loadVideoData();
92 | this.setState({
93 | nowPlay: partStr
94 | });
95 | },
96 | _loadVideoData(){
97 | this.setState({
98 | loading: true
99 | });
100 | if (this._cid !== null) {
101 | var _this = this;
102 | reqwest({
103 | url: Config.base_url + Config.routes.VIDEO_URL + this._cid + "?quality=" + this._quality
104 | , type: 'json'
105 | , method: 'get'
106 | , crossOrigin: true
107 | , error: function (err) {
108 | console.log('error');
109 | }
110 | , success: function (data) {
111 | _this.setState({
112 | loading: false,
113 | data: data
114 | });
115 | }
116 | });
117 | }
118 | },
119 | componentDidMount(){
120 | //初始化cid
121 | this._selectParts("0");
122 | },
123 | getDefaultProps(){
124 | return {
125 | parts: [],
126 | pic: ""
127 | }
128 | },
129 | getInitialState(){
130 | return {
131 | loading: true,
132 | data: null,
133 | nowPlay: "0"
134 | }
135 | },
136 | render(){
137 | var partList = [];
138 | var display = "none";
139 | if (this.props.parts.hasOwnProperty("1")) {
140 | for (var i in this.props.parts) {
141 | if (this.props.parts.hasOwnProperty(i)) {
142 | var active = "";
143 | if (i === this.state.nowPlay) {
144 | active = "active";
145 | }
146 | partList.push({this.props.parts[i].part});
148 | }
149 | }
150 | display = "block";
151 | }
152 |
153 | var commentUrl = Config.routes.GET_COMMENT + this._cid + ".xml";
154 |
155 | return
156 |
157 |
158 | {partList}
159 |
160 |
161 | {this.state.loading ?
:
162 |
}
164 |
165 |
;
166 | }
167 | });
168 |
--------------------------------------------------------------------------------
/src/js/components/SearchContent.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var reqwest = require('reqwest');
3 |
4 | var Config = require('../Config');
5 | var Pager = require('./Pager');
6 | var Loading = require('./Loading');
7 |
8 |
9 | const videoHrefStr = "#/view/";
10 | const bangumiHrefStr = "#/bangumi/";
11 |
12 | const VideoItem = React.createClass({
13 | getDefaultProps(){
14 | return {
15 | data: {
16 | title: "",
17 | cover: "",
18 | param: "",
19 | desc: "",
20 | author: "",
21 | duration: "",
22 | play: 0,
23 | danmaku: 0
24 | }
25 | };
26 | },
27 | render() {
28 | var date = new Date();
29 | date.setTime(this.props.data.pubdate * 1000);
30 |
31 | var linkUrl = videoHrefStr + this.props.data.param;
32 | return ;
48 | }
49 | });
50 |
51 |
52 | const UserItem = React.createClass({
53 | getDefaultProps(){
54 | return {
55 | data: {
56 | title: "",
57 | cover: "",
58 | param: "",
59 | fans: "",
60 | sign: ""
61 | }
62 | };
63 | },
64 | render() {
65 | var date = new Date();
66 | date.setTime(this.props.data.pubdate * 1000);
67 |
68 | var linkUrl = '#';
69 | return ;
83 | }
84 | });
85 |
86 |
87 | const BangumiItem = React.createClass({
88 | getDefaultProps(){
89 | return {
90 | data: {
91 | title: "",
92 | cover: "",
93 | param: "",
94 | cat_desc: "",
95 | total_count: 0
96 | }
97 | }
98 | },
99 | render(){
100 | return
101 |
102 |

103 |
104 |
105 |
{this.props.data.title}
106 |
{this.props.data.cat_desc}
107 |
108 |
集数: {this.props.data.total_count}
109 |
110 |
111 |
;
112 | }
113 | });
114 |
115 |
116 | const Topic = React.createClass({
117 | getDefaultProps(){
118 | return {
119 | data: {
120 | arcurl: "",
121 | author: "",
122 | click: 0,
123 | cover: "",
124 | description: "",
125 | favourite: 0,
126 | keyword: "",
127 | mid: 0,
128 | pubdate: 0,
129 | review: 0,
130 | title: "",
131 | tp_id: 0,
132 | tp_type: 0,
133 | update: 0
134 | }
135 | }
136 | },
137 | render(){
138 | return ;
139 | }
140 | });
141 |
142 | const SearchBlock = React.createClass({
143 | _handleClick(){
144 | var value = this.refs.search_content.value;
145 | this.props.searchCallBack(value);
146 | },
147 | componentDidUpdate(prevProps, prevState){
148 | //input value
149 | this.refs.search_content.setAttribute('value', this.props.keyword);
150 | },
151 | getDefaultProps(){
152 | return {
153 | keyword: "",
154 | searchCallBack: function (keyword) {
155 | console.log(keyword);
156 | }
157 | }
158 | },
159 | render(){
160 | return
161 |
162 |
163 |
164 |
搜索
165 |
166 |
167 |
;
168 | }
169 | });
170 |
171 |
172 | module.exports = React.createClass({
173 | _searchType: "video",
174 | _page: 1,
175 | _order: "totalrank",
176 | _keyword: "",
177 | _loadData(){
178 | this.setState({
179 | loading: true
180 | });
181 | var _this = this;
182 | if (this._searchType == "video") {
183 | reqwest({
184 | url: Config.base_url + Config.routes.SEARCH
185 | , type: 'json'
186 | , method: 'get'
187 | , data: {
188 | content: _this._keyword,
189 | page_size: 20,
190 | page: _this._page,
191 | order: _this._order
192 | }
193 | , crossOrigin: true
194 | , error: function (err) {
195 | console.log('error:' + err);
196 | }
197 | , success: function (data) {
198 | _this.props.cb(_this._keyword);
199 | _this.setState({
200 | list: data.items.archive,
201 | all_page: 500,
202 | loading: false
203 | });
204 | }
205 | });
206 | } else {
207 | reqwest({
208 | url: Config.base_url + Config.routes.SEARCH_BY_TYPE
209 | , type: 'json'
210 | , method: 'get'
211 | , data: {
212 | content: _this._keyword,
213 | page_size: 20,
214 | page: _this._page,
215 | type: _this._searchType
216 | }
217 | , crossOrigin: true
218 | , error: function (err) {
219 | console.log('error:' + err);
220 | }
221 | , success: function (data) {
222 | _this.props.cb(_this._keyword);
223 | _this.setState({
224 | list: data.items,
225 | all_page: data.pages,
226 | loading: false
227 | });
228 | }
229 | });
230 | }
231 | },
232 | _getSearch(content){
233 | this._keyword = content;
234 | this._loadData();
235 | },
236 | _changeOrder(order){
237 | this._order = order;
238 | this._loadData();
239 | },
240 | _changePage(page){
241 | this._page = page;
242 | this._loadData();
243 | $('body,html').animate({scrollTop: 0}, 700);
244 | },
245 | _changeType(type){
246 | this._searchType = type;
247 | this._page = 1;
248 | this._loadData();
249 | },
250 | getInitialState(){
251 | return {
252 | list: [],
253 | all_page: 0,
254 | loading: true
255 | }
256 | },
257 | getDefaultProps(){
258 | return {
259 | keyword: "",
260 | allPage: 20,
261 | cb: function (content) {
262 | }
263 | }
264 | },
265 | componentDidMount(){
266 | this._keyword = this.props.keyword;
267 | this._loadData();
268 | },
269 | componentWillReceiveProps(nextProps){
270 | this._keyword = nextProps.keyword;
271 | this._loadData();
272 | this.setState({
273 | loading: true
274 | });
275 | },
276 | render(){
277 | var renderArr = [];
278 |
279 | for (var i = 0; i < this.state.list.length; i++) {
280 | switch (this._searchType) {
281 | case "video": {
282 | renderArr.push();
283 | break;
284 | }
285 | case "bangumi": {
286 | renderArr.push();
287 | break;
288 | }
289 | case "user": {
290 | renderArr.push();
291 | }
292 | }
293 | }
294 |
295 |
296 | return
297 |
298 |
299 |
300 |
301 | - 视频
303 |
304 | - 番剧
306 |
307 | - UP主
309 |
310 |
311 |
312 |
313 |
314 | {(this._searchType == "video") ?
315 |
316 | - 综合排序
318 |
319 | - 最多点击
321 |
322 | - 最新发布
324 |
325 | - 弹幕
327 |
328 |
329 |
330 |
:
}
331 |
332 |
333 | {(this.state.loading) ?
:
334 |
335 |
336 | {renderArr}
337 |
338 |
341 |
342 |
}
343 |
;
344 | }
345 | });
346 |
--------------------------------------------------------------------------------
/src/js/components/SortHot.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var Config = require('../Config');
3 | var reqwest = require('reqwest');
4 |
5 | const VideoItem = React.createClass({
6 | getDefaultProps(){
7 | return {
8 | data: {
9 | title: "",
10 | cover: "",
11 | param: "",
12 | name: "",
13 | play: "",
14 | reply: "",
15 | danmaku: "",
16 | favourite: ""
17 | }
18 | };
19 | },
20 | getInitialState(){
21 | return {
22 | hrefStr: "#/view/"
23 | };
24 | },
25 | render() {
26 | var linkUrl = this.state.hrefStr + this.props.data.param;
27 | return
28 |
29 |

30 |
31 |
39 |
;
40 | }
41 | });
42 |
43 |
44 | module.exports = React.createClass({
45 | _order: 'hot',
46 | _loadData(){
47 | var _this = this;
48 | reqwest({
49 | url: Config.base_url + Config.routes.TOP_RANK
50 | , type: 'json'
51 | , method: 'get'
52 | , crossOrigin: true
53 | , error: function (err) {
54 | console.log('error');
55 | }
56 | , success: function (data) {
57 | _this.setState({
58 | videoList: data
59 | });
60 | }
61 | });
62 | },
63 | getDefaultProps(){
64 | return {
65 | tid: 0
66 | }
67 | },
68 | getInitialState(){
69 | return {
70 | videoList: []
71 | }
72 | },
73 | componentDidMount(){
74 | this._loadData();
75 | },
76 | render(){
77 | var renderList = [];
78 |
79 | for (var i in this.state.videoList) {
80 | if (i != "num") {
81 | renderList.push();
82 | }
83 | }
84 |
85 | return
86 |
89 |
90 | {renderList}
91 |
92 |
;
93 | }
94 | });
95 |
--------------------------------------------------------------------------------
/src/js/components/SortRank.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var reqwest = require('reqwest');
3 |
4 | var Config = require('../Config');
5 | var Pager = require('./Pager');
6 | var Loading = require('./Loading');
7 |
8 | const VideoItem = React.createClass({
9 | getDefaultProps(){
10 | return {
11 | data: {
12 | title: "",
13 | cover: "",
14 | param: "",
15 | name: "",
16 | play: "",
17 | reply: "",
18 | danmaku: "",
19 | favourite: ""
20 | }
21 | };
22 | },
23 | getInitialState(){
24 | return {
25 | hrefStr: "#/view/"
26 | };
27 | },
28 | render() {
29 | var linkUrl = this.state.hrefStr + this.props.data.param;
30 | return
31 |
32 |
33 |
34 |
35 |

36 |
37 |
38 |
39 |
播放: {this.props.data.play}
40 |
弹幕: {this.props.data.danmaku}
41 |
42 |
43 |
48 |
49 |
;
50 | }
51 | });
52 |
53 | const VideoBlock = React.createClass({
54 | getDefaultProps(){
55 | return {
56 | videoList: []
57 | }
58 | },
59 | render(){
60 | var renderList = [];
61 |
62 | for (var i in this.props.videoList) {
63 | if (i != "num") {
64 | renderList.push();
65 | }
66 | }
67 |
68 | return
69 | {renderList}
70 |
71 |
;
72 | }
73 | });
74 |
75 |
76 | module.exports = React.createClass({
77 | _page: 1,
78 | _order: 'view',
79 | //排序方式
80 | _changeSort(sort){
81 | this._order = sort;
82 | this._page = 1;
83 | this._loadData(this.props.tid);
84 | },
85 | //分页
86 | _changePage(page){
87 | //翻页后大传送术
88 | $('body,html').animate({scrollTop: 0}, 700);
89 | this._page = page;
90 | this._loadData(this.props.tid);
91 | },
92 | _loadData(tid){
93 | this.setState({
94 | loading: true
95 | });
96 | let _this = this;
97 | let labelName = Config.sort_tags[tid];
98 |
99 | reqwest({
100 | url: Config.base_url + Config.routes.SORT_VIDEOS + tid + "?page=" + _this._page + "&order=" + this._order
101 | , type: 'json'
102 | , method: 'get'
103 | , crossOrigin: true
104 | , error: function (err) {
105 | console.log('error:' + err);
106 | }
107 | , success: function (data) {
108 | _this.props.cb(labelName);
109 | _this.setState({
110 | videoList: data,
111 | allPage: 999,
112 | title: labelName,
113 | loading: false
114 | });
115 | }
116 | });
117 | },
118 | getDefaultProps(){
119 | return {
120 | tid: 0,
121 | cb: function (content) {
122 | }
123 | }
124 | },
125 | getInitialState(){
126 | return {
127 | videoList: [],
128 | allPage: 0,
129 | title: "",
130 | loading: true
131 | }
132 | },
133 | componentWillReceiveProps(nextProps){
134 | this._loadData(nextProps.tid);
135 | },
136 | componentDidMount(){
137 | this._loadData(this.props.tid);
138 | },
139 | render(){
140 | var _this = this;
141 |
142 | return
143 |
144 |
{this.state.title}
145 |
146 |
147 |
157 |
158 | {(this.state.loading) ?
:
159 |
160 |
161 |
162 |
163 |
164 |
165 | }
166 |
;
167 | }
168 | });
169 |
--------------------------------------------------------------------------------
/src/js/components/Video.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 | var reqwest = require('reqwest');
3 | var _ = require('lodash');
4 |
5 | var Config = require('../Config');
6 | var Player = require('./Player');
7 | var Loading = require('./Loading');
8 |
9 | const Tags = React.createClass({
10 | getDefaltProps(){
11 | return {
12 | str: ""
13 | };
14 | },
15 | render(){
16 | var tags = _.split(this.props.str, ",");
17 | var renderTags = [];
18 | for (var i in tags) {
19 | renderTags.push({tags[i]})
20 | }
21 | return
22 | {renderTags}
23 |
24 |
;
25 | }
26 | });
27 |
28 | const VideoInfo = React.createClass({
29 | getDefaltProps(){
30 | return {
31 | data: {
32 | author: "",
33 | coins: "",
34 | created_at: "",
35 | description: "",
36 | face: "",
37 | favorites: "",
38 | list: {},
39 | mid: "",
40 | pages: 1,
41 | pic: "",
42 | play: "",
43 | review: "",
44 | tag: "",
45 | tid: 0,
46 | title: "",
47 | typename: "",
48 | video_review: ""
49 | }
50 | };
51 | },
52 | render(){
53 | return
54 |
55 |
56 |
57 |
58 |
59 |
{this.props.data.title}
60 |
61 |
62 |
分类: {this.props.data.typename}
63 |
时间: {this.props.data.created_at}
64 |
65 |
66 |
67 |
播放: {this.props.data.play}
68 |
弹幕: {this.props.data.video_review}
69 |
硬币: {this.props.data.coins}
70 |
71 |
72 |
73 |
83 |
84 |
85 |
86 |
87 |
88 | {this.props.data.list ?
: }
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 | {this.props.data.description}
98 |
99 |
100 |
评论
101 |
(施工中)
102 |
103 |
104 |
105 |
106 | ;
107 | }
108 | });
109 |
110 | module.exports = React.createClass({
111 | _loadData(){
112 | if (this.props.aid !== null) {
113 | var _this = this;
114 | reqwest({
115 | url: Config.base_url + Config.routes.VIDEO_INFO + this.props.aid
116 | , type: 'json'
117 | , method: 'get'
118 | , crossOrigin: true
119 | , error: function (err) {
120 | console.log('error');
121 | }
122 | , success: function (data) {
123 | _this.props.cb(data.title);
124 | _this.setState({
125 | videoInfo: data
126 | });
127 | }
128 | });
129 | }
130 | },
131 | componentDidMount(){
132 | this._loadData();
133 | },
134 | getDefaltProps(){
135 | return {
136 | aid: null,
137 | cb: function (content) {
138 | }
139 | }
140 | },
141 | getInitialState(){
142 | return {
143 | videoInfo: {}
144 | }
145 | },
146 | render(){
147 | return ;
148 | }
149 | });
150 |
--------------------------------------------------------------------------------
/src/js/danmaku/BilibiliParser.js:
--------------------------------------------------------------------------------
1 | function BilibiliParser(xmlDoc) {
2 | var elements = xmlDoc.getElementsByTagName('d');
3 |
4 | var danmakuList = [];
5 | for (var i = 0; i < elements.length; i++) {
6 | if (elements[i].getAttribute('p') != null) {
7 | var opt = elements[i].getAttribute('p').split(',');
8 | if (!elements[i].childNodes[0])
9 | continue;
10 | var text = elements[i].childNodes[0].nodeValue;
11 | var obj = {};
12 | obj.stime = Math.round(parseFloat(opt[0]) * 1000);
13 | obj.mode = parseInt(opt[1]);
14 | obj.size = parseInt(opt[2]);
15 | obj.color = parseInt(opt[3]);
16 | obj.date = parseInt(opt[4]);
17 | obj.pool = parseInt(opt[5]);
18 | obj.position = "absolute";
19 | if (opt[7] != null)
20 | obj.dbid = parseInt(opt[7]);
21 | obj.hash = opt[6];
22 | obj.border = false;
23 | if (obj.mode < 7) {
24 | obj.text = text.replace(/(\/n|\\n|\n|\r\n)/g, "\n");
25 | }
26 | if (obj.text != null)
27 | obj.text = obj.text.replace(/\u25a0/g, "\u2588");
28 | danmakuList.push(obj);
29 | }
30 | }
31 | return danmakuList;
32 | }
33 |
34 | module.exports = BilibiliParser;
35 |
36 |
--------------------------------------------------------------------------------
/src/js/danmaku/CommentManager.js:
--------------------------------------------------------------------------------
1 | var StaticComment = require('./StaticComment');
2 | var ScrollComment = require('./ScrollComment');
3 |
4 |
5 | class CommentManager {
6 | constructor(stage) {
7 | this.commentLine = [];
8 | this.nowLine = [];
9 | this.position = 0;
10 | this.options = {
11 | indexOffset: 0,
12 | className: "cmt",
13 | margin: 1,
14 | global: {
15 | opacity: 1,
16 | scale: 1
17 | },
18 | scroll: {
19 | opacity: 1,
20 | scale: 1
21 | },
22 | limit: 0
23 | };
24 | this.stage = stage;
25 | this.width = stage.offsetWidth;
26 | this.height = stage.offsetHeight;
27 | }
28 |
29 | startTimer() {
30 | for (var i = 0; i < this.nowLine.length; i++) {
31 | if (this.nowLine[i].control) {
32 | this.nowLine[i].start();
33 | }
34 | }
35 | }
36 |
37 | stopTimer() {
38 | for (var i = 0; i < this.nowLine.length; i++) {
39 | if (this.nowLine[i].control) {
40 | this.nowLine[i].stop();
41 | }
42 | }
43 | }
44 |
45 | nowLinePush(pushCmt) {
46 | if (this.nowLine.length === 0) {
47 | this.nowLine.push(pushCmt);
48 | return;
49 | }
50 | if (this.nowLine[this.nowLine.length - 1].offsetY() <= pushCmt.offsetY()) {
51 | this.nowLine.push(pushCmt);
52 | return;
53 | }
54 | if (this.nowLine[0].offsetY() >= pushCmt.offsetY()) {
55 | this.nowLine.unshift(pushCmt);
56 | return;
57 | }
58 | var low = 0;
59 | var high = this.nowLine.length - 1;
60 |
61 | var i = 0;
62 | var insertIndex = 0;
63 | while (low < high) {
64 | i = Math.floor((high + low + 1) / 2);
65 | if (this.nowLine[i - 1].offsetY() <= pushCmt.offsetY() && this.nowLine[i].offsetY() >= pushCmt.offsetY()) {
66 | insertIndex = i;
67 | break;
68 | }
69 | if (this.nowLine[i - 1].offsetY() > pushCmt.offsetY()) {
70 | high = i - 1;
71 | } else {
72 | low = i;
73 | }
74 | }
75 | this.nowLine.splice(insertIndex, 0, pushCmt);
76 | }
77 |
78 | nowLineRemove(removeCmt) {
79 | var index = this.nowLine.indexOf(removeCmt);
80 | if (index >= 0) {
81 | this.nowLine.splice(index, 1);
82 | }
83 | }
84 |
85 | setBounds() {
86 | this.width = this.stage.offsetWidth;
87 | this.height = this.stage.offsetHeight;
88 | };
89 |
90 | init() {
91 | this.setBounds();
92 | this.position = 0;
93 | };
94 |
95 |
96 | //插入弹幕
97 | send(data) {
98 | var cmt;
99 | if (data.mode === 5 || data.mode === 4) {
100 | cmt = new StaticComment(this, data);
101 | } else if (data.mode === 1 || data.mode === 2 || data.mode == 6) {
102 | cmt = new ScrollComment(this, data);
103 | } else {
104 | console.log('不支持的弹幕');
105 | return;
106 | }
107 | cmt.init();
108 | this.stage.appendChild(cmt.dom);
109 | cmt.layout();
110 | this.nowLinePush(cmt);
111 | };
112 |
113 | seek(locateTime) {
114 | this.position = 0;
115 | this.position = this.locate(locateTime);
116 | };
117 |
118 | locate(time) {
119 | for (var i = this.position; i < this.commentLine.length; i++) {
120 | var cm = this.commentLine[i];
121 | if (cm.stime >= time) {
122 | return i;
123 | }
124 | }
125 | return this.commentLine.length;
126 | };
127 |
128 | time(nowTime) {
129 | if (this.nowLine.length === 0 && this.position === this.commentLine.length) {
130 | return;
131 | }
132 |
133 | nowTime -= 1;
134 |
135 | if (this.position < this.commentLine.length) {
136 | var end = this.locate(nowTime);
137 |
138 | for (; this.position < end; this.position++) {
139 | this.send(this.commentLine[this.position]);
140 | }
141 | this.position = end;
142 | }
143 |
144 | var length = this.nowLine.length;
145 | for (var i = 0; i < length; i++) {
146 | var cmt = this.nowLine[i];
147 | if (!cmt.checkTime(nowTime)) {
148 | this.remove(cmt);
149 | length--;
150 | }
151 | }
152 | };
153 |
154 | load(timeLine) {
155 | this.commentLine = timeLine;
156 | this.position = 0;
157 | this.commentLine.sort(function (a, b) {
158 | if (a.stime >= b.stime) {
159 | return 1;
160 | } else {
161 | return -1;
162 | }
163 | });
164 | };
165 |
166 | remove(rmObj) {
167 | this.nowLineRemove(rmObj);
168 | this.stage.removeChild(rmObj.dom);
169 | };
170 |
171 | clear() {
172 | while (this.nowLine.length > 0) {
173 | this.remove(this.nowLine[0]);
174 | }
175 | };
176 | }
177 |
178 | module.exports = CommentManager;
179 |
--------------------------------------------------------------------------------
/src/js/danmaku/CommentObject.js:
--------------------------------------------------------------------------------
1 | class CommentObject {
2 |
3 | constructor(manager, init) {
4 | this.align = 0;
5 | this.index = 0;
6 | this.mode = 1;
7 | this.stime = 0;
8 | this.text = "";
9 | this._size = 20;
10 | this._color = 0xffffff;
11 | this.control = false;
12 | this._border = false;
13 |
14 | this.lifeTime = 4000 * manager.options.global.scale;
15 | this.manager = manager;
16 |
17 | if (init.hasOwnProperty("align")) {
18 | this.align = init["align"];
19 | }
20 | if (init.hasOwnProperty("stime")) {
21 | this.stime = init["stime"];
22 | }
23 | if (init.hasOwnProperty("text")) {
24 | this.text = init["text"];
25 | }
26 | if (init.hasOwnProperty("mode")) {
27 | this.mode = init["mode"];
28 | }
29 | if (init.hasOwnProperty("color")) {
30 | this._color = init["color"];
31 | }
32 | if (init.hasOwnProperty("size")) {
33 | this._size = init["size"];
34 | }
35 | if (init.hasOwnProperty("x")) {
36 | this._x = init["x"];
37 | }
38 | if (init.hasOwnProperty("y")) {
39 | this._y = init["y"];
40 | }
41 | if (init.hasOwnProperty("border")) {
42 | this._border = init["border"];
43 | }
44 | }
45 |
46 | offsetX(x) {
47 | if (x === null || x === undefined) {
48 | if (this._x === null || this._x === undefined) {
49 | if (this.align % 2 === 0) {
50 | this._x = this.dom.offsetLeft - this.manager.stage.offsetLeft;
51 | } else {
52 | this._x = this.manager.stage.offsetWidth - (this.dom.offsetLeft - this.manager.stage.offsetLeft + this.dom.offsetWidth);
53 | }
54 | }
55 | return this._x;
56 | } else {
57 | this._x = x;
58 | if (this.align % 2 === 0) {
59 | this.dom.style.right = this._x + "px";
60 | } else {
61 | this.dom.style.left = this._x + "px";
62 | }
63 | }
64 | };
65 |
66 |
67 | offsetY(y) {
68 | if (y === null || y === undefined) {
69 | if (this._y === null || this._y === undefined) {
70 | if (this.align < 2) {
71 | this._y = this.dom.offsetTop;
72 | } else {
73 | this._y = this.manager.stage.offsetHeight - (this.dom.offsetTop + this.dom.offsetHeight);
74 | }
75 | }
76 | return this._y;
77 | } else {
78 | this._y = y;
79 | if (this.align < 2) {
80 | this.dom.style.top = this._y + "px";
81 | } else {
82 | this.dom.style.top = (this.manager.stage.offsetHeight - y - this.dom.offsetHeight) + "px";
83 | }
84 | }
85 | };
86 |
87 |
88 | Color(c) {
89 | if (c === null || c === undefined) {
90 | return this._color;
91 | } else {
92 | this._color = c;
93 | var color = c.toString(16);
94 | color = color.length >= 6 ? color : new Array(6 - color.length + 1).join("0") + color;
95 | if (color.indexOf('#') !== 0) {
96 | color = '#'.concat(color);
97 | }
98 | this.dom.style.color = color;
99 | if (this._color === 0) {
100 | this.dom.className = this.manager.options.className + " rshadow";
101 | }
102 | }
103 | };
104 |
105 |
106 | Width(w) {
107 | if (w === null || w === undefined) {
108 | if (this._width === null || this._width === undefined) {
109 | this._width = this.dom.offsetWidth;
110 | }
111 | return this._width;
112 | } else {
113 | this._width = w;
114 | this.dom.style.width = this._width + "px";
115 | }
116 | };
117 |
118 |
119 | Height(h) {
120 | if (h === null || h === undefined) {
121 | if (this._height === null || this._height === undefined) {
122 | this._height = this.dom.offsetHeight;
123 | }
124 | return this._height;
125 | } else {
126 | this._height = h;
127 | this.dom.style.height = this._height + "px";
128 | }
129 | };
130 |
131 |
132 | Size(s) {
133 | if (s === null || s === undefined) {
134 | return this._size;
135 | } else {
136 | this._size = s;
137 | this.dom.style.fontSize = this._size + "px";
138 | }
139 | };
140 |
141 |
142 | Border(b) {
143 | if (b === null || b === undefined) {
144 | return this._border;
145 | } else {
146 | this._border = b;
147 | this.dom.style.border = b;
148 | }
149 | };
150 |
151 |
152 | init() {
153 | var dom = document.createElement("div");
154 | dom.className = this.manager.options.className;
155 |
156 | dom.appendChild(document.createTextNode(this.text));
157 |
158 | dom.textContent = this.text;
159 | dom.innerText = this.text;
160 |
161 | this.dom = dom;
162 |
163 | if (this._border) {
164 | dom.style.border = "2px solid red";
165 | }
166 |
167 | this.Color(this._color);
168 | this.Size(this._size);
169 | };
170 |
171 | checkTime(nowTime) {
172 | return (this.stime + this.lifeTime) >= nowTime;
173 | };
174 |
175 |
176 | layout() {
177 | };
178 |
179 |
180 | stop() {
181 | };
182 |
183 | start() {
184 | };
185 |
186 | }
187 |
188 |
189 | module.exports = CommentObject;
190 |
--------------------------------------------------------------------------------
/src/js/danmaku/ScrollComment.js:
--------------------------------------------------------------------------------
1 | var CommentObject = require('./CommentObject');
2 |
3 | class ScrollComment extends CommentObject {
4 | constructor(manager, init) {
5 | super(manager, init);
6 | switch (this.mode) {
7 | case 1:
8 | this.align = 0;
9 | break;
10 | case 2:
11 | this.align = 2;
12 | break;
13 | case 6:
14 | this.align = 1;
15 | }
16 | this.follow = false;
17 | this.control = true;
18 | this.lifeTime *= manager.options.scroll.scale;
19 | this.moving = false;
20 |
21 | //容差
22 | this.timeOffset = 700;
23 | }
24 |
25 | layout() {
26 | var index = 0;
27 | var channel = this.Size() + 2 * this.manager.options.margin;
28 | var offset = 0;
29 | var insertY = -1;
30 | var width = this.Width();
31 |
32 | while (insertY < 0) {
33 | if (index > 1000) {
34 | return;
35 | }
36 | insertY = this._findOffsetY(index, channel, offset);
37 | index++;
38 | offset += this.manager.options.indexOffset;
39 | }
40 | this.index = index - 1;
41 | this.offsetY(insertY);
42 | this.dom.style.right = "-" + width + "px";
43 | this.dom.style.left = "-" + width + "px";
44 |
45 | this.moveAnimation();
46 | };
47 |
48 | _findOffsetY(index, channel, offset) {
49 | var cmObj;
50 | var preY = offset;
51 | for (var i = 0; i < this.manager.nowLine.length; i++) {
52 | cmObj = this.manager.nowLine[i];
53 | if (cmObj.mode === this.mode && cmObj.index === index) {
54 | if (cmObj.offsetY() - preY >= channel) {
55 | return preY;
56 | }
57 | if ((!cmObj.follow) && (cmObj.timeLeft <= (cmObj.lifeTime * 0.5))) {
58 | cmObj.follow = true;
59 | return cmObj.offsetY();
60 | }
61 | preY = cmObj.offsetY() + cmObj.Height();
62 | }
63 | }
64 | if (preY + channel <= this.manager.stage.offsetHeight) {
65 | return preY;
66 | }
67 | return -1;
68 | };
69 |
70 |
71 | transform(trans) {
72 | this.dom.style.transform = trans;
73 | this.dom.style["webkitTransform"] = trans;
74 | this.dom.style["msTransform"] = trans;
75 | this.dom.style["oTransform"] = trans;
76 | };
77 |
78 | moveTransform() {
79 | if (!this.moving) {
80 | var dx = -(this.manager.width + this.Width());
81 | this.transform("translateX(" + dx + "px)");
82 | this.dom.style.transition = "transform " + this.lifeTime + "ms linear";
83 | this.moving = true;
84 | }
85 | };
86 |
87 | moveAnimation() {
88 | var locate = this.align % 2 == 0 ? '-left ' : '-right ';
89 | var animation = "cmt-move" + locate + this.lifeTime / 1000 + "s linear";
90 | this.dom.style.animation = animation;
91 | this.dom.style["-webkit-animation"] = animation;
92 | this.dom.style["-moz-animation"] = animation;
93 | this.dom.style["-o-animation"] = animation;
94 | };
95 |
96 | start() {
97 | this.dom.style["animation-play-state"] = "running";
98 | };
99 |
100 | stop() {
101 | this.dom.style["animation-play-state"] = "paused";
102 | };
103 |
104 |
105 | checkTime(nowTime) {
106 | return this.stime + this.lifeTime + this.timeOffset >= nowTime;
107 | };
108 |
109 | }
110 |
111 | module.exports = ScrollComment;
112 |
113 |
--------------------------------------------------------------------------------
/src/js/danmaku/StaticComment.js:
--------------------------------------------------------------------------------
1 | var CommentObject = require('./CommentObject');
2 |
3 |
4 | class StaticComment extends CommentObject {
5 | constructor(manager, init) {
6 | super(manager, init);
7 | this.align = (this.mode == 4) ? 3 : 0;
8 | }
9 |
10 | _findOffsetY(index, channel, offset) {
11 | //取得起始位置(区别对齐方式)
12 | var preY = offset;
13 | for (var i in this.manager.nowLine) {
14 | var cmObj = this.manager.nowLine[i];
15 | //弹幕同类型同层
16 | if (cmObj.mode === this.mode && cmObj.index === index) {
17 | if (cmObj.offsetY() - preY >= channel) {
18 | return preY;
19 | } else {
20 | preY = cmObj.offsetY() + cmObj.Height();
21 | }
22 | }
23 | }
24 | if (preY + channel <= this.manager.stage.offsetHeight) {
25 | return preY;
26 | }
27 | return -1;
28 | };
29 |
30 | layout() {
31 | var index = 0;
32 | var channel = this.Height() + 2 * this.manager.options.margin;
33 | var offset = 0;
34 | var insertY = -1;
35 |
36 | while (insertY < 0) {
37 | insertY = this._findOffsetY(index, channel, offset);
38 | index++;
39 | offset += this.manager.options.indexOffset;
40 | }
41 |
42 | this.index = index - 1;
43 | this.offsetX(this.manager.stage.offsetLeft + (this.manager.stage.offsetWidth - this.Width()) / 2);
44 | this.offsetY(insertY);
45 | };
46 | }
47 |
48 |
49 | module.exports = StaticComment;
50 |
51 |
--------------------------------------------------------------------------------
/src/js/danmaku/VideojsPlugin.js:
--------------------------------------------------------------------------------
1 | var videojs = require("video.js");
2 | var reqwest = require('reqwest');
3 |
4 | var CommentManager = require("./CommentManager");
5 | var BilibiliParser = require("./BilibiliParser");
6 |
7 | videojs.plugin('initDanmaku', function () {
8 | function Danmu(ele) {
9 | var _this = this;
10 | this.danmuDiv = document.createElement('div');
11 | this.danmuDiv.className = 'vjs-danmu';
12 | ele.el().insertBefore(this.danmuDiv, ele.el().getElementsByClassName('vjs-poster')[0]);
13 |
14 | this.danmuShowControl = document.createElement('div');
15 | this.danmuShowControl.className = 'vjs-danmu-control vjs-menu-button vjs-control';
16 | this.danmuShowControlContent = document.createElement('span');
17 | this.danmuShowControlContent.className = 'vjs-danmu-switch';
18 | this.danmuShowControlContent.innerHTML = '弹幕';
19 | this.danmuShowControl.appendChild(this.danmuShowControlContent);
20 | ele.el().getElementsByClassName('vjs-control-bar')[0].appendChild(this.danmuShowControl);
21 |
22 | //CCL init
23 | this.cmManager = new CommentManager(this.danmuDiv);
24 | //弹幕播放时间
25 | this.cmManager.options.scroll.scale = 3;
26 | this.cmManager.init();
27 | this.cmManager.clear();
28 |
29 | this.cmManager.display = true;
30 |
31 | //弹幕控制绑定
32 | var video = ele.el().children[0];
33 | var lastPosition = 0;
34 | video.addEventListener("progress", function () {
35 | if (lastPosition == video.currentTime) {
36 | video.hasStalled = true;
37 | _this.cmManager.stopTimer();
38 | } else
39 | lastPosition = video.currentTime;
40 | });
41 | //时间轴更新
42 | video.addEventListener("timeupdate", function () {
43 | if (_this.cmManager.display === false) return;
44 | if (video.hasStalled) {
45 | _this.cmManager.startTimer();
46 | video.hasStalled = false;
47 | }
48 | _this.cmManager.time(Math.floor(video.currentTime * 1000));
49 | });
50 |
51 | video.addEventListener("play", function () {
52 | _this.cmManager.startTimer();
53 | });
54 |
55 | video.addEventListener("pause", function () {
56 | _this.cmManager.stopTimer();
57 | });
58 |
59 | video.addEventListener("waiting", function () {
60 | _this.cmManager.stopTimer();
61 | });
62 |
63 | video.addEventListener("playing", function () {
64 | _this.cmManager.startTimer();
65 | });
66 |
67 | video.addEventListener("seeked", function () {
68 | _this.cmManager.seek(Math.floor(video.currentTime * 1000));
69 | _this.cmManager.clear();
70 | });
71 |
72 | if (window) {
73 | window.addEventListener("resize", function () {
74 | _this.cmManager.setBounds();
75 | });
76 | }
77 | this.danmuShowControl.addEventListener("click", function () {
78 | if (_this.cmManager.display === true) {
79 | _this.cmManager.clear();
80 | _this.cmManager.display = false;
81 | _this.danmuShowControlContent.innerHTML = "无";
82 | } else {
83 | _this.cmManager.display = true;
84 | _this.danmuShowControlContent.innerHTML = "弹幕";
85 | }
86 | });
87 |
88 |
89 | this.load = function (url) {
90 | reqwest({
91 | url: url
92 | , type: 'xml'
93 | , method: 'get'
94 | , crossOrigin: true
95 | , error: function (err) {
96 | console.log('error:', err);
97 | }
98 | , success: function (data) {
99 | if (data != null) {
100 | _this.cmManager.load(BilibiliParser(data));
101 | }
102 | }
103 | });
104 | };
105 |
106 | return this;
107 | }
108 |
109 | this.danmu = new Danmu(this);
110 | });
111 |
112 |
--------------------------------------------------------------------------------
/src/js/page/BangumiIndexPage.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var BangumiIndex = require('../components/BangumiIndex');
4 | var BangumiList = require('../components/BangumiList');
5 |
6 |
7 | module.exports = React.createClass({
8 | componentDidMount(){
9 | document.title = "BH5 | 番剧";
10 | },
11 | render(){
12 | return
13 |
14 |
15 |
;
16 | }
17 | });
18 |
--------------------------------------------------------------------------------
/src/js/page/BangumiInfoPage.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var BangumiInfo = require('../components/BangumiInfo');
4 |
5 |
6 | function titleCallback(content) {
7 | document.title = "BH5 | 番剧:" + content;
8 | }
9 |
10 | module.exports = React.createClass({
11 | render(){
12 | return
13 |
;
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/src/js/page/IndexPage.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var IndexBanner = require('../components/IndexBanner');
4 | var IndexHot = require('../components/IndexHot');
5 | var AllRank = require('../components/AllRank');
6 |
7 | module.exports = React.createClass({
8 | render(){
9 | return
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
;
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/src/js/page/SearchPage.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var SearchContent = require('../components/SearchContent');
4 |
5 |
6 | function titleCallback(content) {
7 | document.title = "BH5 | 搜索:" + content;
8 | }
9 |
10 | module.exports = React.createClass({
11 | render(){
12 | return
13 |
;
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/src/js/page/SortPage.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var SortRank = require('../components/SortRank');
4 | var SortHot = require('../components/SortHot');
5 |
6 | function titleCallback(content) {
7 | document.title = "BH5 | 分类:" + content;
8 | }
9 |
10 | module.exports = React.createClass({
11 | render(){
12 | return ;
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/src/js/page/ViewPage.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | var Video = require('../components/Video');
4 |
5 |
6 | function titleCallback(content) {
7 | document.title = "BH5 | " + content;
8 | }
9 |
10 |
11 | module.exports = React.createClass({
12 | render(){
13 | return ;
14 | }
15 | });
16 |
--------------------------------------------------------------------------------
/src/js/parts/Error.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | getDefaultProps(){
5 | return {
6 | message: "加载失败...."
7 | };
8 | },
9 | render() {
10 | return
11 |
{this.props.message}
12 |
;
13 | }
14 | });
--------------------------------------------------------------------------------
/src/js/parts/Footer.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | getInitialState(){
5 | return {
6 | data: null
7 | };
8 | },
9 | componentDidMount(){
10 | this.setState({
11 | data: {}
12 | });
13 | },
14 | render() {
15 | return ;
27 | }
28 | });
--------------------------------------------------------------------------------
/src/js/parts/Loading.js:
--------------------------------------------------------------------------------
1 | var React = require('react');
2 |
3 | module.exports = React.createClass({
4 | render() {
5 | return ;
8 | }
9 | });
10 |
--------------------------------------------------------------------------------
/src/js/utils/VideojsHotKeys.js:
--------------------------------------------------------------------------------
1 | /*
2 | * use Video.js Hotkeys by Chris Dougherty
3 | *
4 | * https://github.com/ctd1500/videojs-hotkeys
5 | */
6 |
7 | var videojs = require("video.js");
8 |
9 | videojs.plugin('hotkeys', function (options) {
10 | var player = this;
11 | var pEl = player.el();
12 | var doc = document;
13 | var def_options = {
14 | volumeStep: 0.1,
15 | seekStep: 5,
16 | enableMute: true,
17 | enableVolumeScroll: true,
18 | enableFullscreen: true,
19 | enableNumbers: true,
20 | enableJogStyle: false,
21 | alwaysCaptureHotkeys: false,
22 | enableModifiersForNumbers: true,
23 | playPauseKey: playPauseKey,
24 | rewindKey: rewindKey,
25 | forwardKey: forwardKey,
26 | volumeUpKey: volumeUpKey,
27 | volumeDownKey: volumeDownKey,
28 | muteKey: muteKey,
29 | fullscreenKey: fullscreenKey,
30 | customKeys: {}
31 | };
32 |
33 | var cPlay = 1,
34 | cRewind = 2,
35 | cForward = 3,
36 | cVolumeUp = 4,
37 | cVolumeDown = 5,
38 | cMute = 6,
39 | cFullscreen = 7;
40 |
41 | // Use built-in merge function from Video.js v5.0+ or v4.4.0+
42 | var mergeOptions = videojs.mergeOptions || videojs.util.mergeOptions;
43 | options = mergeOptions(def_options, options || {});
44 |
45 | var volumeStep = options.volumeStep,
46 | seekStep = options.seekStep,
47 | enableMute = options.enableMute,
48 | enableVolumeScroll = options.enableVolumeScroll,
49 | enableFull = options.enableFullscreen,
50 | enableNumbers = options.enableNumbers,
51 | enableJogStyle = options.enableJogStyle,
52 | alwaysCaptureHotkeys = options.alwaysCaptureHotkeys,
53 | enableModifiersForNumbers = options.enableModifiersForNumbers;
54 |
55 | // Set default player tabindex to handle keydown and doubleclick events
56 | if (!pEl.hasAttribute('tabIndex')) {
57 | pEl.setAttribute('tabIndex', '-1');
58 | }
59 |
60 | // Remove player outline to fix video performance issue
61 | pEl.style.outline = "none";
62 |
63 | if (alwaysCaptureHotkeys || !player.autoplay()) {
64 | player.one('play', function () {
65 | pEl.focus(); // Fixes the .vjs-big-play-button handing focus back to body instead of the player
66 | });
67 | }
68 |
69 | player.on('userinactive', function () {
70 | // When the control bar fades, re-apply focus to the player if last focus was a control button
71 | var cancelFocusingPlayer = function () {
72 | clearTimeout(focusingPlayerTimeout);
73 | };
74 | var focusingPlayerTimeout = setTimeout(function () {
75 | player.off('useractive', cancelFocusingPlayer);
76 | if (doc.activeElement.parentElement == pEl.querySelector('.vjs-control-bar')) {
77 | pEl.focus();
78 | }
79 | }, 10);
80 |
81 | player.one('useractive', cancelFocusingPlayer);
82 | });
83 |
84 | player.on('play', function () {
85 | // Fix allowing the YouTube plugin to have hotkey support.
86 | var ifblocker = pEl.querySelector('.iframeblocker');
87 | if (ifblocker && ifblocker.style.display === '') {
88 | ifblocker.style.display = "block";
89 | ifblocker.style.bottom = "39px";
90 | }
91 | });
92 |
93 | var keyDown = function keyDown(event) {
94 | var ewhich = event.which, curTime;
95 | var ePreventDefault = event.preventDefault;
96 | // When controls are disabled, hotkeys will be disabled as well
97 | if (player.controls()) {
98 |
99 | // Don't catch keys if any control buttons are focused, unless alwaysCaptureHotkeys is true
100 | var activeEl = doc.activeElement;
101 | if (alwaysCaptureHotkeys ||
102 | activeEl == pEl ||
103 | activeEl == pEl.querySelector('.vjs-tech') ||
104 | activeEl == pEl.querySelector('.vjs-control-bar') ||
105 | activeEl == pEl.querySelector('.iframeblocker')) {
106 |
107 | switch (checkKeys(event, player)) {
108 | // Spacebar toggles play/pause
109 | case cPlay:
110 | ePreventDefault();
111 | if (alwaysCaptureHotkeys) {
112 | // Prevent control activation with space
113 | event.stopPropagation();
114 | }
115 |
116 | if (player.paused()) {
117 | player.play();
118 | } else {
119 | player.pause();
120 | }
121 | break;
122 |
123 | // Seeking with the left/right arrow keys
124 | case cRewind: // Seek Backward
125 | ePreventDefault();
126 | curTime = player.currentTime() - seekStep;
127 | // The flash player tech will allow you to seek into negative
128 | // numbers and break the seekbar, so try to prevent that.
129 | if (player.currentTime() <= seekStep) {
130 | curTime = 0;
131 | }
132 | player.currentTime(curTime);
133 | break;
134 | case cForward: // Seek Forward
135 | ePreventDefault();
136 | player.currentTime(player.currentTime() + seekStep);
137 | break;
138 |
139 | // Volume control with the up/down arrow keys
140 | case cVolumeDown:
141 | ePreventDefault();
142 | if (!enableJogStyle) {
143 | player.volume(player.volume() - volumeStep);
144 | } else {
145 | curTime = player.currentTime() - 1;
146 | if (player.currentTime() <= 1) {
147 | curTime = 0;
148 | }
149 | player.currentTime(curTime);
150 | }
151 | break;
152 | case cVolumeUp:
153 | ePreventDefault();
154 | if (!enableJogStyle) {
155 | player.volume(player.volume() + volumeStep);
156 | } else {
157 | player.currentTime(player.currentTime() + 1);
158 | }
159 | break;
160 |
161 | // Toggle Mute with the M key
162 | case cMute:
163 | if (enableMute) {
164 | player.muted(!player.muted());
165 | }
166 | break;
167 |
168 | // Toggle Fullscreen with the F key
169 | case cFullscreen:
170 | if (enableFull) {
171 | if (player.isFullscreen()) {
172 | player.exitFullscreen();
173 | } else {
174 | player.requestFullscreen();
175 | }
176 | }
177 | break;
178 |
179 | default:
180 | // Number keys from 0-9 skip to a percentage of the video. 0 is 0% and 9 is 90%
181 | if ((ewhich > 47 && ewhich < 59) || (ewhich > 95 && ewhich < 106)) {
182 | // Do not handle if enableModifiersForNumbers set to false and keys are Ctrl, Cmd or Alt
183 | if (enableModifiersForNumbers || !(event.metaKey || event.ctrlKey || event.altKey)) {
184 | if (enableNumbers) {
185 | var sub = 48;
186 | if (ewhich > 95) {
187 | sub = 96;
188 | }
189 | var number = ewhich - sub;
190 | ePreventDefault();
191 | player.currentTime(player.duration() * number * 0.1);
192 | }
193 | }
194 | }
195 |
196 | // Handle any custom hotkeys
197 | for (var customKey in options.customKeys) {
198 | var customHotkey = options.customKeys[customKey];
199 | // Check for well formed custom keys
200 | if (customHotkey && customHotkey.key && customHotkey.handler) {
201 | // Check if the custom key's condition matches
202 | if (customHotkey.key(event)) {
203 | ePreventDefault();
204 | customHotkey.handler(player, options);
205 | }
206 | }
207 | }
208 | }
209 | }
210 | }
211 | };
212 |
213 | var doubleClick = function doubleClick(event) {
214 | // When controls are disabled, hotkeys will be disabled as well
215 | if (player.controls()) {
216 |
217 | // Don't catch clicks if any control buttons are focused
218 | var activeEl = event.relatedTarget || event.toElement || doc.activeElement;
219 | if (activeEl == pEl ||
220 | activeEl == pEl.querySelector('.vjs-tech') ||
221 | activeEl == pEl.querySelector('.iframeblocker')) {
222 |
223 | if (enableFull) {
224 | if (player.isFullscreen()) {
225 | player.exitFullscreen();
226 | } else {
227 | player.requestFullscreen();
228 | }
229 | }
230 | }
231 | }
232 | };
233 |
234 | var mouseScroll = function mouseScroll(event) {
235 | // When controls are disabled, hotkeys will be disabled as well
236 | if (player.controls()) {
237 | var activeEl = event.relatedTarget || event.toElement || doc.activeElement;
238 | if (alwaysCaptureHotkeys ||
239 | activeEl == pEl ||
240 | activeEl == pEl.querySelector('.vjs-tech') ||
241 | activeEl == pEl.querySelector('.iframeblocker') ||
242 | activeEl == pEl.querySelector('.vjs-control-bar')) {
243 |
244 | if (enableVolumeScroll) {
245 | event = window.event || event;
246 | var delta = Math.max(-1, Math.min(1, (event.wheelDelta || -event.detail)));
247 | event.preventDefault();
248 |
249 | if (delta == 1) {
250 | player.volume(player.volume() + volumeStep);
251 | } else if (delta == -1) {
252 | player.volume(player.volume() - volumeStep);
253 | }
254 | }
255 | }
256 | }
257 | };
258 |
259 | var checkKeys = function checkKeys(e, player) {
260 | // Allow some modularity in defining custom hotkeys
261 |
262 | // Play/Pause check
263 | if (options.playPauseKey(e, player)) {
264 | return cPlay;
265 | }
266 |
267 | // Seek Backward check
268 | if (options.rewindKey(e, player)) {
269 | return cRewind;
270 | }
271 |
272 | // Seek Forward check
273 | if (options.forwardKey(e, player)) {
274 | return cForward;
275 | }
276 |
277 | // Volume Up check
278 | if (options.volumeUpKey(e, player)) {
279 | return cVolumeUp;
280 | }
281 |
282 | // Volume Down check
283 | if (options.volumeDownKey(e, player)) {
284 | return cVolumeDown;
285 | }
286 |
287 | // Mute check
288 | if (options.muteKey(e, player)) {
289 | return cMute;
290 | }
291 |
292 | // Fullscreen check
293 | if (options.fullscreenKey(e, player)) {
294 | return cFullscreen;
295 | }
296 | };
297 |
298 | function playPauseKey(e) {
299 | // Space bar or MediaPlayPause
300 | return (e.which === 32 || e.which === 179);
301 | }
302 |
303 | function rewindKey(e) {
304 | // Left Arrow or MediaRewind
305 | return (e.which === 37 || e.which === 177);
306 | }
307 |
308 | function forwardKey(e) {
309 | // Right Arrow or MediaForward
310 | return (e.which === 39 || e.which === 176);
311 | }
312 |
313 | function volumeUpKey(e) {
314 | // Up Arrow
315 | return (e.which === 38);
316 | }
317 |
318 | function volumeDownKey(e) {
319 | // Down Arrow
320 | return (e.which === 40);
321 | }
322 |
323 | function muteKey(e) {
324 | // M key
325 | return (e.which === 77);
326 | }
327 |
328 | function fullscreenKey(e) {
329 | // F key
330 | return (e.which === 70);
331 | }
332 |
333 | player.on('keydown', keyDown);
334 | player.on('dblclick', doubleClick);
335 | player.on('mousewheel', mouseScroll);
336 | player.on("DOMMouseScroll", mouseScroll);
337 |
338 | return this;
339 | });
340 |
341 |
--------------------------------------------------------------------------------
/src/styles/bangumi.css:
--------------------------------------------------------------------------------
1 | /*index info*/
2 | .bangumi-banner-block {
3 | margin: 20px auto;
4 | width: 640px;
5 | height: 200px;
6 |
7 | position: relative;
8 | overflow: hidden;
9 | }
10 |
11 | .bangumi-banner {
12 | width: 640px;
13 | height: 200px;
14 | }
15 |
16 | .area-banner > h2 {
17 | margin: 20px 10px;
18 | font-size: 25px;
19 | font-weight: bold;
20 | color: #666;
21 | }
22 |
23 | .bangumi_item {
24 | width: 200px;
25 | height: 120px;
26 | margin: 10px 20px;
27 |
28 | border-radius: 4px;
29 | border: 1px solid #f6f6f6;;
30 | overflow: hidden;
31 |
32 | -webkit-transition: border .2s ease;
33 | -moz-transition: border .2s ease;
34 | -ms-transition: border .2s ease;
35 | -o-transition: border .2s ease;
36 | transition: border .2s ease;
37 | }
38 |
39 | .bangumi_item:hover {
40 | border: 1px solid #666;
41 | box-shadow: 0 0 5px rgb(179, 178, 178);
42 | }
43 |
44 | .bangumi_item:hover > .info > .title {
45 | color: #e04270;
46 | }
47 |
48 | .bangumi_item > .img-small {
49 | width: 99px;
50 | height: 119px;
51 | overflow: hidden;
52 | }
53 |
54 | .bangumi_item > .info {
55 | width: 99px;
56 | height: 119px;
57 | padding: 0 5px;
58 | overflow: hidden;
59 | }
60 |
61 | .bangumi_item > .info > .title {
62 | display: block;
63 |
64 | padding: 5px 5px;
65 | position: relative;
66 | font-size: 13px;
67 | font-weight: bold;
68 | color: #000;
69 |
70 | height: 60px;
71 | overflow: hidden;
72 | }
73 |
74 | .bangumi_item > .info > .other {
75 | display: block;
76 |
77 | padding: 10px 5px;
78 | position: relative;
79 | font-size: 11px;
80 | font-weight: bold;
81 | color: #666;
82 |
83 | max-height: 50px;
84 | overflow: hidden;
85 | }
86 |
87 | .img-small > img {
88 | width: 100%;
89 | }
90 |
91 | .list-bangumi-block {
92 | width: 960px;
93 | max-height: 140px;
94 | overflow: hidden;
95 | margin: 20px auto;
96 | }
97 |
98 | .toggle-btn {
99 | width: 100px;
100 | height: 30px;
101 | margin: 10px auto;
102 |
103 | border-radius: 4px;
104 | border: 1px solid #666;
105 | }
106 |
107 | .toggle-btn > a {
108 | display: block;
109 | text-align: center;
110 | margin: 5px auto;
111 | font-size: 13px;
112 | font-weight: bold;
113 | color: #555;
114 | }
115 |
116 | .toggle-btn > a:hover {
117 | color: #e04270;
118 | }
119 |
120 | /*bangumi\sp info*/
121 |
122 | .bangumi-header {
123 | width: 1000px;
124 | min-height: 400px;
125 | margin: 20px auto;
126 | background-color: #fff;
127 | }
128 |
129 | .bangumi-header > h2 {
130 | display: block;
131 | position: relative;
132 | left: 150px;
133 | top: 25px;
134 | width: 600px;
135 |
136 | color: #525659;
137 | overflow: hidden;
138 | line-height: 24px;
139 | text-overflow: ellipsis;
140 | font-weight: 400;
141 | white-space: nowrap;
142 | font-size: 20px
143 | }
144 |
145 | .bangumi-header-img {
146 | float: left;
147 | position: relative;
148 | left: 50px;
149 | top: 25px;
150 | width: 200px;
151 | height: 293px;
152 | }
153 |
154 | .bangumi-header-img > img {
155 | width: 200px;
156 | }
157 |
158 | .bangumi-header-info {
159 | float: left;
160 | position: relative;
161 | left: 150px;
162 | top: 80px;
163 | width: 600px;
164 | min-height: 250px;
165 | color: #666;
166 | font-weight: bold;
167 | }
168 |
169 | .bangumi-header-info > p {
170 | font-size: 14px;
171 | line-height: 150%;
172 | font-weight: 100;
173 | }
174 |
175 | .bangumi-header-info > span {
176 | font-size: 14px;
177 | line-height: 150%;
178 | font-weight: 100;
179 | }
180 |
181 | .bangumi-part {
182 | background-color: #fff;
183 | width: 1000px;
184 | min-height: 200px;
185 | }
186 |
187 | .bangumi-part > ul {
188 | margin: 0 0;
189 | position: relative;
190 | top: 40px;
191 | left: 35px;
192 | width: 90%;
193 | }
194 |
195 | .bangumi-part > p {
196 | position: relative;
197 | top: 20px;
198 | left: 30px;
199 | font-size: 25px;
200 | font-weight: bold;
201 | color: #666;
202 | }
203 |
204 | .bangumi-part > ul > li {
205 | display: block;
206 | margin: 5px 10px;
207 | min-width: 64px;
208 | padding: 0 5px;
209 |
210 | height: 32px;
211 | border: 1px solid #999;
212 | border-radius: 4px;
213 |
214 | -webkit-transition: background-color .2s ease;
215 | -moz-transition: background-color .2s ease;
216 | -ms-transition: background-color .2s ease;
217 | -o-transition: background-color .2s ease;
218 | transition: background-color .2s ease;
219 | }
220 |
221 | .bangumi-part > ul > li > a {
222 | display: block;
223 | height: 32px;
224 | text-decoration: none;
225 | text-align: center;
226 | }
227 |
228 | .bangumi-part > ul > li:hover {
229 | background-color: #aeb7bf;
230 | }
231 |
232 | .bangumi-part-span {
233 | text-decoration: none;
234 | color: #999;
235 | position: relative;
236 | top: 6px;
237 | }
238 |
239 | .bangumi-part > ul > li:hover .video_more_span {
240 | color: #fff;
241 | }
242 |
243 | .bangumi-season {
244 | background-color: #fff;
245 | margin: 20px auto;
246 | padding: 0 10px;
247 | width: 1000px;
248 | }
249 |
--------------------------------------------------------------------------------
/src/styles/player.css:
--------------------------------------------------------------------------------
1 | .video-js .vjs-danmu {
2 | overflow: hidden;
3 | position: absolute;
4 | top: 0;
5 | left: 0;
6 | bottom: 0;
7 | right: 0;
8 | pointer-events: none;
9 | -webkit-touch-callout: none;
10 | -webkit-user-select: none;
11 | -khtml-user-select: none;
12 | -moz-user-select: none;
13 | -ms-user-select: none;
14 | user-select: none;
15 | }
16 |
17 | .video-js .vjs-danmu .cmt {
18 | white-space: nowrap;
19 | padding: 3px 0 0 0;
20 | margin: 0;
21 | line-height: 100%;
22 | font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
23 | font-weight: 400;
24 | text-decoration: none;
25 | letter-spacing: 0;
26 | position: absolute;
27 | word-break: keep-all;
28 | text-wrap: none;
29 | border: 0 !important;
30 | -webkit-text-size-adjust: none;
31 | text-size-adjust: none;
32 | }
33 |
34 | .video-js .vjs-danmu .cmt.noshadow {
35 | text-shadow: none !important;
36 | }
37 |
38 | .video-js .vjs-danmu .cmt.rshadow {
39 | text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white !important;
40 | }
41 |
42 | .vjs-danmu-control .vjs-menu-icon:before {
43 | content: '\f110';
44 | font-family: VideoJS;
45 | font-weight: normal;
46 | font-style: normal;
47 | font-size: 1.8em;
48 | line-height: 1.67em;
49 |
50 | }
51 |
52 | .vjs-danmu-control .vjs-danmu-switch {
53 | font-size: 1em;
54 | line-height: 3em;
55 | position: absolute;
56 | top: 0;
57 | left: 0;
58 | width: 100%;
59 | height: 100%;
60 | text-align: center;
61 | box-sizing: inherit;
62 | }
63 |
64 | /* animation */
65 | .cmt {
66 | will-change: transform;
67 | }
68 |
69 | @keyframes cmt-move-left {
70 | from {
71 | transform: translateX(100%);
72 | }
73 | }
74 |
75 | @keyframes cmt-move-right {
76 | to {
77 | transform: translateX(-100%);
78 | }
79 | }
80 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
(施工中)
138 |