├── LICENSE
├── README.md
├── client
├── index.html
└── js
│ ├── apiCDNP2P.js
│ ├── peer.js
│ ├── videojs-media-sources.js
│ ├── videojs.hls.orig.js
│ └── videojs
│ ├── demo.captions.vtt
│ ├── demo.html
│ ├── font
│ ├── vjs.eot
│ ├── vjs.svg
│ ├── vjs.ttf
│ └── vjs.woff
│ ├── lang
│ ├── ar.js
│ ├── de.js
│ ├── es.js
│ ├── fr.js
│ ├── hu.js
│ ├── it.js
│ ├── ja.js
│ ├── ko.js
│ ├── nl.js
│ ├── pt-BR.js
│ ├── ru.js
│ ├── uk.js
│ └── zh.js
│ ├── video-js.css
│ ├── video-js.less
│ ├── video-js.min.css
│ ├── video-js.swf
│ ├── video.dev.js
│ └── video.js
└── server
└── peerjs-server
├── README.md
├── app.json
├── bin
└── peerjs
├── lib
├── index.js
├── server.js
└── util.js
├── package.json
└── test
└── server.js
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | PCDN
2 | ====
3 |
4 |
5 | PCDN is an Peer to peer/P2P CDN for video based on an hybride solution
6 |
7 | It's work with **Peerjs** , **Videojs** and **WebRTC**.
8 |
9 | It's a prof of concept so don't focus on the code quality.
10 |
11 | I hope you found it interresting and feel free to contact me
12 |
13 | An example here [http://pcdn.jairagne.ovh](http://pcdn.jairagne.ovh)
14 |
15 | Riquirement
16 | ==========
17 |
18 | - Videojs video player
19 | - Compatible Browsers
20 | - HLS video
21 |
22 |
23 |
24 | Client
25 | =====
26 |
27 | Copy past on your video page this code
28 |
29 |
30 |
31 |
34 |
35 | Configuration:
36 |
37 | - host: host of the server
38 | - port: port of the peerjs server
39 | - key: api key of my peerjs server
40 | - debug: Level of debug 0-3 see peerjs configuration
41 | - more: [Peerjs API configuration](http://peerjs.com/)
42 |
43 | Server
44 | =====
45 |
46 | **PCDN server**
47 |
48 | My PCDN server is free to use. feel free to make your test on it.
49 | For production mode, my advice is to do it by yourself.
50 | Or use existing solution like Streemroot or Peer5 ....
51 | [good article here](http://blog.uppersideconferences.com/the-non-telecom-side-of-webrtc-data-channel/)
52 |
53 | host: pcdn.jairagne.ovh
54 | port:9000
55 | key:peerjs
56 |
57 | **Your own PCDN server**
58 |
59 | $ cd server/peerjs-server
60 | $ npm install
61 | $ cd bin
62 | $ node peerjs --help
63 |
64 |
65 | Contact
66 | ======
67 | Twitter : [@adelskott](https://twitter.com/adelskott)
68 |
69 | TODO
70 | ====
71 |
72 | - Landing page for inactive users
73 | - Expose client API
74 | - Refactor code
75 | - Limit the client share to 5
76 | - Replace Peejs to use a proper server with faye
77 | - Use a redis or Elasticsearch instead of memory storage
78 | - Create a server dashboard for stats
79 | - Automatic reconnection server
80 | - Too many failure bybass P2P
81 |
82 |
--------------------------------------------------------------------------------
/client/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
48 |
49 |
50 |
51 |
52 |
122 |
123 |
124 |
134 |
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/client/js/apiCDNP2P.js:
--------------------------------------------------------------------------------
1 |
2 | var myBase = {};
3 | var myBaseUrl = {};
4 | var coreCache = {};
5 | var statP2P = {
6 | p2p:0,
7 | cdn:0,
8 | leechers:0,
9 | seeders:0,
10 | requests:0
11 | };
12 |
13 | (function(videojs){
14 | videojs.APIP2P = {};
15 | videojs.APIP2P.startConnect = function (options) {
16 | var self = this;
17 | var peer = new Peer(options);
18 | videojs.APIP2P.options = options;
19 | videojs.APIP2P.peer = peer;
20 | peer.on('connection', function (conn){
21 | // manage /...
22 | myBase[conn.peer] = conn;
23 | videojs.APIP2P.initializing(conn, null);
24 | });
25 | peer.on("error", function (error){
26 | console.log("ERROR P2P peerjs", error.type);
27 | if (error.type == "peer-unavailable"){
28 | var id = error.message.substring("Could not connect to peer ".length);
29 | videojs.APIP2P.cleanbase(id);
30 | var obj = {
31 | response : null
32 | };
33 | var ca = self.callbacks[id];
34 | if (ca){
35 | // perdu un leecher
36 | statP2P.leechers--;
37 | ca.callback.call(obj, obj, "error no peer", ca.message.url);
38 | delete self.callbacks[id];
39 | }else{
40 | // perdu un seeder
41 | }
42 | }
43 | console.log("ERROR",error.message);
44 | });
45 | };
46 |
47 |
48 | videojs.APIP2P.callbacks = {};
49 |
50 |
51 | videojs.APIP2P.cleanbase = function (id) {
52 | if (myBase[id])
53 | delete myBase[id];
54 | for (var i = 0; i < Object.keys(myBaseUrl).length; i++) {
55 | var url = Object.keys(myBaseUrl)[i];
56 | if(myBaseUrl[url][id])
57 | delete myBaseUrl[url][id];
58 | }
59 | };
60 |
61 | videojs.APIP2P.sendMyBase = function (conn) {
62 | var base = {};
63 | for (var i = 0; i < Object.keys(myBaseUrl).length; i++) {
64 | var url = Object.keys(myBaseUrl)[i];
65 | base[url] = Object.keys(myBaseUrl[url]);
66 | }
67 | conn.send({
68 | type:"ABASE",
69 | data:base,
70 | id:videojs.APIP2P.peer.id
71 | });
72 | };
73 | videojs.APIP2P.initializing = function (conn, leacher){
74 | if (!conn){
75 | console.log("RRRR", "conn error",conn);
76 | return;
77 | }
78 | var self = this;
79 | // conn.on('error', function (error){
80 | // console.log("PEER ERROR", conn.peer, error);
81 | // videojs.APIP2P.cleanbase(conn.peer);
82 | // });
83 | var cleanfct = function(conn){
84 | videojs.APIP2P.cleanbase(conn.peer);
85 | var obj = {
86 | response : null
87 | };
88 | var ca = self.callbacks[conn.peer];
89 | if (ca){
90 | ca.callback.call(obj, "error", ca.message.url);
91 | delete self.callbacks[conn.peer];
92 | }
93 | };
94 | conn.on('error', function (error){
95 | console.log("PEER ERROR P2P", conn.peer, error);
96 | cleanfct(conn);
97 | });
98 | conn.on('disconnected', function (error){
99 | console.log("PEER disconnected P2P", conn.peer, error);
100 | cleanfct(conn);
101 | });
102 | conn.on('close', function (error){
103 | console.log("PEER close P2P", conn.peer, error);
104 | cleanfct(conn);
105 | });
106 | conn.on('open', function (){
107 | // send my base
108 | videojs.APIP2P.sendMyBase(conn);
109 |
110 | conn.on('data', function (data){
111 | //console.log("RCV data");
112 | console.log("RCV data",conn.peer,data);
113 | // managing data
114 | if (data.type == "DATA"){
115 | var obj = {
116 | response : data.data
117 | };
118 | var ca = self.callbacks[conn.peer];
119 | // TODO I'm Leecher for url
120 | if (data.data)
121 | videojs.APIP2P.imLeecher(data.url, videojs.APIP2P.peer.id, data.data);
122 | if (!ca)
123 | return;
124 | ca.callback.call(obj, obj, data.data == null, ca.message.url);
125 | delete self.callbacks[conn.peer];
126 | }
127 |
128 | if (data.type == "ASK"){
129 | // if i have the content
130 |
131 | if (coreCache[data.url]){
132 | console.log("send data");
133 | conn.send({
134 | type: "DATA",
135 | data:coreCache[data.url],
136 | url: data.url
137 | });
138 | }else{
139 | console.log("NO data");
140 | conn.send({
141 | type: "DATA",
142 | url: data.url
143 | });
144 | }
145 | }
146 | if (data.type == "UBASE"){
147 | var all = data.data;
148 | if (!myBaseUrl[data.url])
149 | myBaseUrl[data.url] = {};
150 | myBaseUrl[data.url][data.id] = conn;
151 | }
152 | if (data.type == "ABASE"){
153 | var all = data.data;
154 | for (var i = 0; i < Object.keys(all).length; i++) {
155 | var u = Object.keys(all)[i];
156 | if (!myBaseUrl[u]){
157 | myBaseUrl[u]= [];
158 | }
159 | for (var j = 0; j < all[u].length; j++){
160 | var l = all[u][j];
161 | if (l == videojs.APIP2P.peer.id)
162 | continue;
163 | if (!myBaseUrl[u][l]){
164 | myBaseUrl[u][l] = myBase[l] || 1 ;
165 | }
166 | }
167 | }
168 | console.log("My Base",Object.keys(myBaseUrl));
169 | }
170 | });
171 | // if callbacks ask
172 | if (self.callbacks[conn.peer]){
173 | conn.send(self.callbacks[conn.peer].message);
174 | }
175 | });
176 | };
177 | videojs.APIP2P.xhrP2P = function (leechers, url, callback){
178 | // connect to all leechers if no connected
179 | var selectIndex = Math.floor(Math.random() * leechers.length);
180 | var error = false;
181 | for (var i = 0; i < leechers.length; i++) {
182 | var leecher = leechers[i];
183 | if (!myBase[leecher]){
184 | var conn = this.peer.connect(leecher);
185 | if (!conn){
186 | if (i == selectIndex){
187 | error = true;
188 | }
189 | continue;
190 | }
191 | myBase[leecher] = conn;
192 | myBaseUrl[url][leechers[i]] = conn;
193 | // select 1
194 | if (i == selectIndex){
195 | // ask for content
196 | this.callbacks[leechers[i]] = {
197 | callback: callback,
198 | message: {
199 | type: 'ASK',
200 | url: url
201 | }
202 | };
203 | // fire timer to timeout
204 | }
205 | // add inteligene for each leacher
206 | this.initializing(conn,leechers[i]);
207 | }else if (i == selectIndex){
208 | var conn = myBase[leecher];
209 | this.callbacks[leecher] = {
210 | callback: callback,
211 | message: {
212 | type: 'ASK',
213 | url: url
214 | }
215 | };
216 | conn.send(this.callbacks[leecher].message);
217 | }
218 | }
219 | if (error){
220 | callback.call({response:null}, "error", url);
221 | }
222 | };
223 | videojs.APIP2P.updateLeechers = function (url, callback){
224 | console.log("Update leechers",url);
225 | var options = {
226 | method: 'GET',
227 | timeout: 45 * 1000
228 | };
229 | var checkurl = "http://"+videojs.APIP2P.options.host+":"+videojs.APIP2P.options.port+"/peerjs/url/"+window.btoa(url);
230 | var request = new window.XMLHttpRequest();
231 | request.open(options.method, checkurl);
232 | request.onreadystatechange = function() {
233 | if (this.readyState !== 4) {
234 | return;
235 | }
236 | if (this.response && this.status == 200) {
237 | var leechers = JSON.parse(this.response);
238 | for (var i = 0; i < leechers.length; i++) {
239 | if (leechers[i] == videojs.APIP2P.peer.id){
240 | // si c'est moi
241 | leechers.splice(i,1);
242 | i--;
243 | }else{
244 | myBaseUrl[url][leechers[i]] = 1;
245 | }
246 | }
247 | callback(leechers);
248 | } else {
249 | callback([]);
250 | }
251 | };
252 | request.send(null);
253 | };
254 |
255 | videojs.APIP2P.imLeecher = function (url, id, data){
256 | coreCache[url] = data;
257 | var options = {
258 | method: 'GET',
259 | timeout: 45 * 1000
260 | };
261 | var checkurl = "http://"+videojs.APIP2P.options.host+":"+videojs.APIP2P.options.port+"/peerjs/url/"+window.btoa(url)+"/"+id;
262 | var request = new window.XMLHttpRequest();
263 | request.open(options.method, checkurl);
264 | request.onreadystatechange = function() {
265 | if (this.readyState !== 4) {
266 | return;
267 | }
268 | if (this.response && this.status == 200) {
269 | console.log("I'm Leecher for :", url);
270 | } else {
271 | console.log("ERROR setting leecher for :", url);
272 | }
273 | };
274 | request.send(null);
275 |
276 | // say to all my leecher that i'm leacher of this content
277 | console.log(myBase);
278 | for (var i = 0; i < Object.keys(myBase).length; i++) {
279 | var l = Object.keys(myBase)[i];
280 | if (myBase[l]){
281 | myBase[l].send({
282 | type: "UBASE",
283 | url:url,
284 | id:videojs.APIP2P.peer.id
285 | });
286 | }
287 | };
288 | };
289 |
290 | })(window.videojs);
291 | (function(videojs){
292 | /**
293 | * Creates and sends an XMLHttpRequest.
294 | * TODO - expose video.js core's XHR and use that instead
295 | *
296 | * @param options {string | object} if this argument is a string, it
297 | * is intrepreted as a URL and a simple GET request is
298 | * inititated. If it is an object, it should contain a `url`
299 | * property that indicates the URL to request and optionally a
300 | * `method` which is the type of HTTP request to send.
301 | * @param callback (optional) {function} a function to call when the
302 | * request completes. If the request was not successful, the first
303 | * argument will be falsey.
304 | * @return {object} the XMLHttpRequest that was initiated.
305 | */
306 | videojs.Hls.xhr = function(url_C, callback) {
307 | // return videojs.Hls.xhrCDN(url_C, callback);
308 | // console.log(url_C);
309 | try {
310 | var url = url_C;
311 | if (typeof url_C === 'object') {
312 | url = url_C.url;
313 | }
314 |
315 | console.log("Call url", url);
316 | var self = this;
317 | if (url.indexOf(".ts") < 0){
318 | if (!myBaseUrl[url]){
319 | myBaseUrl[url] = {};//responseType:"arraybuffer"
320 | }
321 | return videojs.Hls.xhrCDN(url, callback);
322 | }else {
323 | if (!myBaseUrl[url]){
324 | myBaseUrl[url] = {};
325 | }
326 | if (Object.keys(myBaseUrl[url]).length > 0){
327 | // have leacher
328 | videojs.Hls.xhrP2P(Object.keys(myBaseUrl[url]), url, callback);
329 | console.log("I know leechers");
330 | // update leachers
331 | videojs.APIP2P.updateLeechers(url, function (leechers){});
332 | return {
333 | abort:function(){
334 | console.log("========================================================================");
335 | }
336 | };
337 | }
338 | }
339 | if (typeof callback !== 'function') {
340 | callback = function() {};
341 | }
342 | // videojs.Hls.xhrCDN(url, callback);
343 |
344 | console.log("Want leechers");
345 | videojs.APIP2P.updateLeechers(url, function (leechers){
346 | if (leechers.length){
347 | videojs.Hls.xhrP2P(leechers, url, callback);
348 | }else{
349 | videojs.Hls.xhrCDN(url, callback);
350 | }
351 | });
352 | return {
353 | abort:function(){
354 | console.log("========================================================================");
355 | }
356 | };
357 | }catch (e){
358 | console.log(e);
359 | }
360 | return {
361 | abort:function(){
362 | console.log("========================================================================");
363 | }
364 | };
365 | };
366 |
367 | videojs.Hls.xhrP2P = function(leechers, url, callback) {
368 | console.log("CALL P2P", url);
369 | var sender = {
370 | requestTime: new Date().getTime()
371 | };
372 | videojs.APIP2P.xhrP2P(leechers,url,function(obj, error, url_cb){
373 | if (error){
374 | // leecher fail
375 | return videojs.Hls.xhrCDN(url, callback);
376 | }
377 | sender.responseTime = new Date().getTime();
378 | sender = videojs.util.mergeOptions(sender,{
379 | roundTripTime : sender.responseTime - sender.requestTime,
380 | bytesReceived : obj.response.byteLength || obj.response.length,
381 | status:200
382 | });
383 | sender.bandwidth = Math.floor((sender.bytesReceived / sender.roundTripTime) * 8 * 1000),
384 | sender.responseType = "arraybuffer";
385 | sender = videojs.util.mergeOptions(sender,obj);
386 | console.log(sender);
387 | statP2P.p2p += sender.bytesReceived;
388 | callback.call(sender,false,url);
389 | });
390 | };
391 |
392 |
393 |
394 | videojs.Hls.xhrCDN = function(url, callback) {
395 | console.log("CALL CDN", url);
396 | var
397 | options = {
398 | method: 'GET',
399 | timeout: 45 * 1000
400 | },
401 | request,
402 | abortTimeout;
403 |
404 | if (typeof callback !== 'function') {
405 | callback = function() {};
406 | }
407 |
408 | if (typeof url === 'object') {
409 | options = videojs.util.mergeOptions(options, url);
410 | url = options.url;
411 | }
412 | if (url.indexOf(".ts") > -1){
413 | options.responseType = "arraybuffer";
414 | }
415 |
416 | request = new window.XMLHttpRequest();
417 | request.open(options.method, url);
418 | request.url = url;
419 | request.requestTime = new Date().getTime();
420 |
421 | if (options.responseType) {
422 | request.responseType = options.responseType;
423 | }
424 | if (options.withCredentials) {
425 | request.withCredentials = true;
426 | }
427 | if (options.timeout) {
428 | abortTimeout = window.setTimeout(function() {
429 | if (request.readyState !== 4) {
430 | request.timedout = true;
431 | request.abort();
432 | }
433 | }, options.timeout);
434 | }
435 |
436 | request.onreadystatechange = function() {
437 | // wait until the request completes
438 | if (this.readyState !== 4) {
439 | return;
440 | }
441 |
442 | // clear outstanding timeouts
443 | window.clearTimeout(abortTimeout);
444 |
445 | // request timeout
446 | if (request.timedout) {
447 | return callback.call(this, 'timeout', url);
448 | }
449 |
450 | // request aborted or errored
451 | if (this.status >= 400 || this.status === 0) {
452 | return callback.call(this, true, url);
453 | }
454 |
455 | if (this.response) {
456 | this.responseTime = new Date().getTime();
457 | this.roundTripTime = this.responseTime - this.requestTime;
458 | this.bytesReceived = this.response.byteLength || this.response.length;
459 | this.bandwidth = Math.floor((this.bytesReceived / this.roundTripTime) * 8 * 1000);
460 | statP2P.cdn += this.bytesReceived;
461 | }
462 | videojs.APIP2P.imLeecher(url, videojs.APIP2P.peer.id, this.response);
463 | //console.log(this);
464 | return callback.call(this, false, url);
465 | };
466 | request.send(null);
467 | return request;
468 | };
469 |
470 | })(window.videojs);
471 |
472 |
473 | window.apiCDNP2P = function(options){
474 | // Videojs hls wrapper
475 | if (window.videojs && window.videojs.Hls){
476 | var baseopt = {host:"127.0.0.1",port:"9000",key: 'peerjs',debug:3};
477 | baseopt = window.videojs.util.mergeOptions(baseopt, options);
478 | window.videojs.APIP2P.startConnect(baseopt);
479 | }
480 | };
481 |
--------------------------------------------------------------------------------
/client/js/videojs-media-sources.js:
--------------------------------------------------------------------------------
1 | (function(window){
2 | var urlCount = 0,
3 | NativeMediaSource = window.MediaSource || window.WebKitMediaSource || {},
4 | nativeUrl = window.URL || {},
5 | EventEmitter,
6 | flvCodec = /video\/flv; codecs=["']vp6,aac["']/,
7 | objectUrlPrefix = 'blob:vjs-media-source/';
8 |
9 | EventEmitter = function(){};
10 | EventEmitter.prototype.init = function(){
11 | this.listeners = [];
12 | };
13 | EventEmitter.prototype.addEventListener = function(type, listener){
14 | if (!this.listeners[type]){
15 | this.listeners[type] = [];
16 | }
17 | this.listeners[type].unshift(listener);
18 | };
19 | EventEmitter.prototype.trigger = function(event){
20 | var listeners = this.listeners[event.type] || [],
21 | i = listeners.length;
22 | while (i--) {
23 | listeners[i](event);
24 | }
25 | };
26 |
27 | // extend the media source APIs
28 |
29 | // Media Source
30 | videojs.MediaSource = function(){
31 | var self = this;
32 | videojs.MediaSource.prototype.init.call(this);
33 |
34 | this.sourceBuffers = [];
35 | this.readyState = 'closed';
36 | this.listeners = {
37 | sourceopen: [function(event){
38 | // find the swf where we will push media data
39 | self.swfObj = document.getElementById(event.swfId);
40 | self.readyState = 'open';
41 |
42 | // trigger load events
43 | if (self.swfObj) {
44 | self.swfObj.vjs_load();
45 | }
46 | }],
47 | webkitsourceopen: [function(event){
48 | self.trigger({
49 | type: 'sourceopen'
50 | });
51 | }]
52 | };
53 | };
54 | videojs.MediaSource.prototype = new EventEmitter();
55 |
56 | // create a new source buffer to receive a type of media data
57 | videojs.MediaSource.prototype.addSourceBuffer = function(type){
58 | var sourceBuffer;
59 |
60 | // if this is an FLV type, we'll push data to flash
61 | if (flvCodec.test(type)) {
62 | // Flash source buffers
63 | sourceBuffer = new videojs.SourceBuffer(this);
64 | } else {
65 | // native source buffers
66 | sourceBuffer = this.nativeSource.addSourceBuffer.apply(this.nativeSource, arguments);
67 | }
68 |
69 | this.sourceBuffers.push(sourceBuffer);
70 | return sourceBuffer;
71 | };
72 | videojs.MediaSource.prototype.endOfStream = function(){
73 | this.swfObj.vjs_endOfStream();
74 | this.readyState = 'ended';
75 | };
76 |
77 | // store references to the media sources so they can be connected
78 | // to a video element (a swf object)
79 | videojs.mediaSources = {};
80 | // provide a method for a swf object to notify JS that a media source is now open
81 | videojs.MediaSource.open = function(msObjectURL, swfId){
82 | var ms = videojs.mediaSources[msObjectURL];
83 |
84 | if (ms) {
85 | ms.trigger({
86 | type: 'sourceopen',
87 | swfId: swfId
88 | });
89 | } else {
90 | throw new Error('Media Source not found (Video.js)');
91 | }
92 | };
93 |
94 | // Source Buffer
95 | videojs.SourceBuffer = function(source){
96 | videojs.SourceBuffer.prototype.init.call(this);
97 | this.source = source;
98 | this.buffer = [];
99 | };
100 | videojs.SourceBuffer.prototype = new EventEmitter();
101 |
102 | // accept video data and pass to the video (swf) object
103 | videojs.SourceBuffer.prototype.appendBuffer = function(uint8Array){
104 | var binary = '',
105 | i = 0,
106 | len = uint8Array.byteLength,
107 | b64str;
108 |
109 | this.buffer.push(uint8Array);
110 |
111 | // base64 encode the bytes
112 | for (i = 0; i < len; i++) {
113 | binary += String.fromCharCode(uint8Array[i])
114 | }
115 | b64str = window.btoa(binary);
116 |
117 | this.trigger({type:'update'});
118 |
119 | // bypass normal ExternalInterface calls and pass xml directly
120 | // EI can be slow by default
121 | this.source.swfObj.CallFunction(''
123 | + b64str
124 | + '');
125 |
126 |
127 | this.trigger({type:'updateend'});
128 | };
129 |
130 | // URL
131 | videojs.URL = {
132 | createObjectURL: function(object){
133 | var url = objectUrlPrefix + urlCount;
134 |
135 | urlCount++;
136 |
137 | // setup the mapping back to object
138 | videojs.mediaSources[url] = object;
139 |
140 | return url;
141 | }
142 | };
143 |
144 | // plugin
145 | videojs.plugin('mediaSource', function(options){
146 | var player = this;
147 |
148 | player.on('loadstart', function(){
149 | var url = player.currentSrc(),
150 | trigger = function(event){
151 | mediaSource.trigger(event);
152 | },
153 | mediaSource;
154 |
155 | if (player.techName === 'Html5' && url.indexOf(objectUrlPrefix) === 0) {
156 | // use the native media source implementation
157 | mediaSource = videojs.mediaSources[url];
158 |
159 | if (!mediaSource.nativeUrl) {
160 | // initialize the native source
161 | mediaSource.nativeSource = new NativeMediaSource();
162 | mediaSource.nativeSource.addEventListener('sourceopen', trigger, false);
163 | mediaSource.nativeSource.addEventListener('webkitsourceopen', trigger, false);
164 | mediaSource.nativeUrl = nativeUrl.createObjectURL(mediaSource.nativeSource);
165 | }
166 | player.src(mediaSource.nativeUrl);
167 | }
168 | });
169 | });
170 |
171 | })(this);
172 |
--------------------------------------------------------------------------------
/client/js/videojs/demo.captions.vtt:
--------------------------------------------------------------------------------
1 | WEBVTT
2 |
3 | 00:00.700 --> 00:04.110
4 | Captions describe all relevant audio for the hearing impaired.
5 | [ Heroic music playing for a seagull ]
6 |
7 | 00:04.500 --> 00:05.000
8 | [ Splash!!! ]
9 |
10 | 00:05.100 --> 00:06.000
11 | [ Sploosh!!! ]
12 |
13 | 00:08.000 --> 00:09.225
14 | [ Splash...splash...splash splash splash ]
15 |
16 | 00:10.525 --> 00:11.255
17 | [ Splash, Sploosh again ]
18 |
19 | 00:13.500 --> 00:14.984
20 | Dolphin: eeeEEEEEeeee!
21 |
22 | 00:14.984 --> 00:16.984
23 | Dolphin: Squawk! eeeEEE?
24 |
25 | 00:25.000 --> 00:28.284
26 | [ A whole ton of splashes ]
27 |
28 | 00:29.500 --> 00:31.000
29 | Mine. Mine. Mine.
30 |
31 | 00:34.300 --> 00:36.000
32 | Shark: Chomp
33 |
34 | 00:36.800 --> 00:37.900
35 | Shark: CHOMP!!!
36 |
37 | 00:37.861 --> 00:41.193
38 | EEEEEEOOOOOOOOOOWHALENOISE
39 |
40 | 00:42.593 --> 00:45.611
41 | [ BIG SPLASH ]
--------------------------------------------------------------------------------
/client/js/videojs/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Video.js | HTML5 Video Player
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
20 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/client/js/videojs/font/vjs.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Iragne/PCDN/4aa1f4eb3bb28f6f03fcdcef883d5f2213931bd3/client/js/videojs/font/vjs.eot
--------------------------------------------------------------------------------
/client/js/videojs/font/vjs.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/client/js/videojs/font/vjs.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Iragne/PCDN/4aa1f4eb3bb28f6f03fcdcef883d5f2213931bd3/client/js/videojs/font/vjs.ttf
--------------------------------------------------------------------------------
/client/js/videojs/font/vjs.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Iragne/PCDN/4aa1f4eb3bb28f6f03fcdcef883d5f2213931bd3/client/js/videojs/font/vjs.woff
--------------------------------------------------------------------------------
/client/js/videojs/lang/ar.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("ar",{
2 | "Play": "تشغيل",
3 | "Pause": "ايقاف",
4 | "Current Time": "الوقت الحالي",
5 | "Duration Time": "Dauer",
6 | "Remaining Time": "الوقت المتبقي",
7 | "Stream Type": "نوع التيار",
8 | "LIVE": "مباشر",
9 | "Loaded": "تم التحميل",
10 | "Progress": "التقدم",
11 | "Fullscreen": "ملء الشاشة",
12 | "Non-Fullscreen": "غير ملء الشاشة",
13 | "Mute": "صامت",
14 | "Unmuted": "غير الصامت",
15 | "Playback Rate": "معدل التشغيل",
16 | "Subtitles": "الترجمة",
17 | "subtitles off": "ايقاف الترجمة",
18 | "Captions": "التعليقات",
19 | "captions off": "ايقاف التعليقات",
20 | "Chapters": "فصول",
21 | "You aborted the video playback": "لقد ألغيت تشغيل الفيديو",
22 | "A network error caused the video download to fail part-way.": "تسبب خطأ في الشبكة بفشل تحميل الفيديو بالكامل.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "لا يمكن تحميل الفيديو بسبب فشل في الخادم أو الشبكة ، أو فشل بسبب عدم امكانية قراءة تنسيق الفيديو.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "تم ايقاف تشغيل الفيديو بسبب مشكلة فساد أو لأن الفيديو المستخدم يستخدم ميزات غير مدعومة من متصفحك.",
25 | "No compatible source was found for this video.": "فشل العثور على أي مصدر متوافق مع هذا الفيديو."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/de.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("de",{
2 | "Play": "Wiedergabe",
3 | "Pause": "Pause",
4 | "Current Time": "Aktueller Zeitpunkt",
5 | "Duration Time": "Dauer",
6 | "Remaining Time": "Verbleibende Zeit",
7 | "Stream Type": "Streamtyp",
8 | "LIVE": "LIVE",
9 | "Loaded": "Geladen",
10 | "Progress": "Status",
11 | "Fullscreen": "Vollbild",
12 | "Non-Fullscreen": "Kein Vollbild",
13 | "Mute": "Ton aus",
14 | "Unmuted": "Ton ein",
15 | "Playback Rate": "Wiedergabegeschwindigkeit",
16 | "Subtitles": "Untertitel",
17 | "subtitles off": "Untertitel aus",
18 | "Captions": "Untertitel",
19 | "captions off": "Untertitel aus",
20 | "Chapters": "Kapitel",
21 | "You aborted the video playback": "Sie haben die Videowiedergabe abgebrochen.",
22 | "A network error caused the video download to fail part-way.": "Der Videodownload ist aufgrund eines Netzwerkfehlers fehlgeschlagen.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "Das Video konnte nicht geladen werden, da entweder ein Server- oder Netzwerkfehler auftrat oder das Format nicht unterstützt wird.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Die Videowiedergabe wurde entweder wegen eines Problems mit einem beschädigten Video oder wegen verwendeten Funktionen, die vom Browser nicht unterstützt werden, abgebrochen.",
25 | "No compatible source was found for this video.": "Für dieses Video wurde keine kompatible Quelle gefunden."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/es.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("es",{
2 | "Play": "Reproducción",
3 | "Pause": "Pausa",
4 | "Current Time": "Tiempo reproducido",
5 | "Duration Time": "Duración total",
6 | "Remaining Time": "Tiempo restante",
7 | "Stream Type": "Tipo de secuencia",
8 | "LIVE": "DIRECTO",
9 | "Loaded": "Cargado",
10 | "Progress": "Progreso",
11 | "Fullscreen": "Pantalla completa",
12 | "Non-Fullscreen": "Pantalla no completa",
13 | "Mute": "Silenciar",
14 | "Unmuted": "No silenciado",
15 | "Playback Rate": "Velocidad de reproducción",
16 | "Subtitles": "Subtítulos",
17 | "subtitles off": "Subtítulos desactivados",
18 | "Captions": "Subtítulos especiales",
19 | "captions off": "Subtítulos especiales desactivados",
20 | "Chapters": "Capítulos",
21 | "You aborted the video playback": "Ha interrumpido la reproducción del vídeo.",
22 | "A network error caused the video download to fail part-way.": "Un error de red ha interrumpido la descarga del vídeo.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "No se ha podido cargar el vídeo debido a un fallo de red o del servidor o porque el formato es incompatible.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La reproducción de vídeo se ha interrumpido por un problema de corrupción de datos o porque el vídeo precisa funciones que su navegador no ofrece.",
25 | "No compatible source was found for this video.": "No se ha encontrado ninguna fuente compatible con este vídeo."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/fr.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("fr",{
2 | "Play": "Lecture",
3 | "Pause": "Pause",
4 | "Current Time": "Temps actuel",
5 | "Duration Time": "Durée",
6 | "Remaining Time": "Temps restant",
7 | "Stream Type": "Type de flux",
8 | "LIVE": "EN DIRECT",
9 | "Loaded": "Chargé",
10 | "Progress": "Progression",
11 | "Fullscreen": "Plein écran",
12 | "Non-Fullscreen": "Fenêtré",
13 | "Mute": "Sourdine",
14 | "Unmuted": "Son activé",
15 | "Playback Rate": "Vitesse de lecture",
16 | "Subtitles": "Sous-titres",
17 | "subtitles off": "Sous-titres désactivés",
18 | "Captions": "Sous-titres",
19 | "captions off": "Sous-titres désactivés",
20 | "Chapters": "Chapitres",
21 | "You aborted the video playback": "Vous avez interrompu la lecture de la vidéo.",
22 | "A network error caused the video download to fail part-way.": "Une erreur de réseau a interrompu le téléchargement de la vidéo.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "Cette vidéo n'a pas pu être chargée, soit parce que le serveur ou le réseau a échoué ou parce que le format n'est pas reconnu.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La lecture de la vidéo a été interrompue à cause d'un problème de corruption ou parce que la vidéo utilise des fonctionnalités non prises en charge par votre navigateur.",
25 | "No compatible source was found for this video.": "Aucune source compatible n'a été trouvée pour cette vidéo."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/hu.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("hu",{
2 | "Play": "Lejátszás",
3 | "Pause": "Szünet",
4 | "Current Time": "Aktuális időpont",
5 | "Duration Time": "Hossz",
6 | "Remaining Time": "Hátralévő idő",
7 | "Stream Type": "Adatfolyam típusa",
8 | "LIVE": "ÉLŐ",
9 | "Loaded": "Betöltve",
10 | "Progress": "Állapot",
11 | "Fullscreen": "Teljes képernyő",
12 | "Non-Fullscreen": "Normál méret",
13 | "Mute": "Némítás",
14 | "Unmuted": "Némítás kikapcsolva",
15 | "Playback Rate": "Lejátszási sebesség",
16 | "Subtitles": "Feliratok",
17 | "subtitles off": "Feliratok kikapcsolva",
18 | "Captions": "Magyarázó szöveg",
19 | "captions off": "Magyarázó szöveg kikapcsolva",
20 | "Chapters": "Fejezetek",
21 | "You aborted the video playback": "Leállította a lejátszást",
22 | "A network error caused the video download to fail part-way.": "Hálózati hiba miatt a videó részlegesen töltődött le.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "A videó nem tölthető be hálózati vagy kiszolgálói hiba miatt, vagy a formátuma nem támogatott.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "A lejátszás adatsérülés miatt leállt, vagy a videó egyes tulajdonságait a böngészője nem támogatja.",
25 | "No compatible source was found for this video.": "Nincs kompatibilis forrás ehhez a videóhoz."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/it.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("it",{
2 | "Play": "Play",
3 | "Pause": "Pausa",
4 | "Current Time": "Orario attuale",
5 | "Duration Time": "Durata",
6 | "Remaining Time": "Tempo rimanente",
7 | "Stream Type": "Tipo del Streaming",
8 | "LIVE": "LIVE",
9 | "Loaded": "Caricato",
10 | "Progress": "Stato",
11 | "Fullscreen": "Schermo intero",
12 | "Non-Fullscreen": "Chiudi schermo intero",
13 | "Mute": "Muto",
14 | "Unmuted": "Audio",
15 | "Playback Rate": "Tasso di riproduzione",
16 | "Subtitles": "Sottotitoli",
17 | "subtitles off": "Senza sottotitoli",
18 | "Captions": "Sottotitoli non udenti",
19 | "captions off": "Senza sottotitoli non udenti",
20 | "Chapters": "Capitolo",
21 | "You aborted the video playback": "La riproduzione del filmato è stata interrotta.",
22 | "A network error caused the video download to fail part-way.": "Il download del filmato è stato interrotto a causa di un problema rete.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "Il filmato non può essere caricato a causa di un errore nel server o nella rete o perché il formato non viene supportato.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "La riproduzione del filmato è stata interrotta a causa di un file danneggiato o per l’utilizzo di impostazioni non supportate dal browser.",
25 | "No compatible source was found for this video.": "Non ci sono fonti compatibili per questo filmato."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/ja.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("ja",{
2 | "Play": "再生",
3 | "Pause": "一時停止",
4 | "Current Time": "現在の時間",
5 | "Duration Time": "長さ",
6 | "Remaining Time": "残りの時間",
7 | "Stream Type": "ストリームの種類",
8 | "LIVE": "ライブ",
9 | "Loaded": "ロード済み",
10 | "Progress": "進行状況",
11 | "Fullscreen": "フルスクリーン",
12 | "Non-Fullscreen": "フルスクリーン以外",
13 | "Mute": "ミュート",
14 | "Unmuted": "ミュート解除",
15 | "Playback Rate": "再生レート",
16 | "Subtitles": "サブタイトル",
17 | "subtitles off": "サブタイトル オフ",
18 | "Captions": "キャプション",
19 | "captions off": "キャプション オフ",
20 | "Chapters": "チャプター",
21 | "You aborted the video playback": "動画再生を中止しました",
22 | "A network error caused the video download to fail part-way.": "ネットワーク エラーにより動画のダウンロードが途中で失敗しました",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "サーバーまたはネットワークのエラー、またはフォーマットがサポートされていないため、動画をロードできませんでした",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "破損の問題、またはお使いのブラウザがサポートしていない機能が動画に使用されていたため、動画の再生が中止されました",
25 | "No compatible source was found for this video.": "この動画に対して互換性のあるソースが見つかりませんでした"
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/ko.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("ko",{
2 | "Play": "재생",
3 | "Pause": "일시중지",
4 | "Current Time": "현재 시간",
5 | "Duration Time": "지정 기간",
6 | "Remaining Time": "남은 시간",
7 | "Stream Type": "스트리밍 유형",
8 | "LIVE": "라이브",
9 | "Loaded": "로드됨",
10 | "Progress": "진행",
11 | "Fullscreen": "전체 화면",
12 | "Non-Fullscreen": "전체 화면 해제",
13 | "Mute": "음소거",
14 | "Unmuted": "음소거 해제",
15 | "Playback Rate": "재생 비율",
16 | "Subtitles": "서브타이틀",
17 | "subtitles off": "서브타이틀 끄기",
18 | "Captions": "자막",
19 | "captions off": "자막 끄기",
20 | "Chapters": "챕터",
21 | "You aborted the video playback": "비디오 재생을 취소했습니다.",
22 | "A network error caused the video download to fail part-way.": "네트워크 오류로 인하여 비디오 일부를 다운로드하지 못 했습니다.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "비디오를 로드할 수 없습니다. 서버 혹은 네트워크 오류 때문이거나 지원되지 않는 형식 때문일 수 있습니다.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "비디오 재생이 취소됐습니다. 비디오가 손상되었거나 비디오가 사용하는 기능을 브라우저에서 지원하지 않는 것 같습니다.",
25 | "No compatible source was found for this video.": "비디오에 호환되지 않는 소스가 있습니다."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/nl.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("nl",{
2 | "Play": "Afspelen",
3 | "Pause": "Pauze",
4 | "Current Time": "Huidige Tijd",
5 | "Duration Time": "Looptijd",
6 | "Remaining Time": "Resterende Tijd",
7 | "Stream Type": "Stream Type",
8 | "LIVE": "LIVE",
9 | "Loaded": "Geladen",
10 | "Progress": "Status",
11 | "Fullscreen": "Volledig scherm",
12 | "Non-Fullscreen": "Geen volledig scherm",
13 | "Mute": "Geluid Uit",
14 | "Unmuted": "Geluid Aan",
15 | "Playback Rate": "Weergave Rate",
16 | "Subtitles": "Ondertiteling",
17 | "subtitles off": "Ondertiteling uit",
18 | "Captions": "Onderschriften",
19 | "captions off": "Onderschriften uit",
20 | "Chapters": "Hoofdstukken",
21 | "You aborted the video playback": "Je hebt de video weergave afgebroken.",
22 | "A network error caused the video download to fail part-way.": "De video download is mislukt door een netwerkfout.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "De video kon niet worden geladen, veroorzaakt door een server of netwerkfout of het formaat word niet ondersteund.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "De video weergave is afgebroken omdat deze beschadigd is of de video gebruikt functionaliteit die niet door je browser word ondersteund.",
25 | "No compatible source was found for this video.": "Voor deze video is geen ondersteunde bron gevonden."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/pt-BR.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("pt-BR",{
2 | "Play": "Tocar",
3 | "Pause": "Pause",
4 | "Current Time": "Tempo",
5 | "Duration Time": "Duração",
6 | "Remaining Time": "Tempo Restante",
7 | "Stream Type": "Tipo de Stream",
8 | "LIVE": "AO VIVO",
9 | "Loaded": "Carregado",
10 | "Progress": "Progressão",
11 | "Fullscreen": "Tela Cheia",
12 | "Non-Fullscreen": "Tela Normal",
13 | "Mute": "Mudo",
14 | "Unmuted": "Habilitar Som",
15 | "Playback Rate": "Velocidade",
16 | "Subtitles": "Legendas",
17 | "subtitles off": "Sem Legendas",
18 | "Captions": "Anotações",
19 | "captions off": "Sem Anotações",
20 | "Chapters": "Capítulos",
21 | "You aborted the video playback": "Você parou a execução de vídeo.",
22 | "A network error caused the video download to fail part-way.": "Um erro na rede fez o vídeo parar parcialmente.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "O vídeo não pode ser carregado, ou porque houve um problema com sua rede ou pelo formato do vídeo não ser suportado.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "A Execução foi interrompida por um problema com o vídeo ou por seu navegador não dar suporte ao seu formato.",
25 | "No compatible source was found for this video.": "Não foi encontrada fonte de vídeo compatível."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/ru.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("ru",{
2 | "Play": "Воспроизвести",
3 | "Pause": "Приостановить",
4 | "Current Time": "Текущее время",
5 | "Duration Time": "Продолжительность",
6 | "Remaining Time": "Оставшееся время",
7 | "Stream Type": "Тип потока",
8 | "LIVE": "ОНЛАЙН",
9 | "Loaded": "Загрузка",
10 | "Progress": "Прогресс",
11 | "Fullscreen": "Полноэкранный режим",
12 | "Non-Fullscreen": "Неполноэкранный режим",
13 | "Mute": "Без звука",
14 | "Unmuted": "Со звуком",
15 | "Playback Rate": "Скорость воспроизведения",
16 | "Subtitles": "Субтитры",
17 | "subtitles off": "Субтитры выкл.",
18 | "Captions": "Подписи",
19 | "captions off": "Подписи выкл.",
20 | "Chapters": "Главы",
21 | "You aborted the video playback": "Вы прервали воспроизведение видео",
22 | "A network error caused the video download to fail part-way.": "Ошибка сети вызвала сбой во время загрузки видео.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "Невозможно загрузить видео из-за сетевого или серверного сбоя либо формат не поддерживается.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Воспроизведение видео было приостановлено из-за повреждения либо в связи с тем, что видео использует функции, неподдерживаемые вашим браузером.",
25 | "No compatible source was found for this video.": "Совместимые источники для этого видео отсутствуют."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/uk.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("uk",{
2 | "Play": "Відтворити",
3 | "Pause": "Призупинити",
4 | "Current Time": "Поточний час",
5 | "Duration Time": "Тривалість",
6 | "Remaining Time": "Час, що залишився",
7 | "Stream Type": "Тип потоку",
8 | "LIVE": "НАЖИВО",
9 | "Loaded": "Завантаження",
10 | "Progress": "Прогрес",
11 | "Fullscreen": "Повноекранний режим",
12 | "Non-Fullscreen": "Неповноекранний режим",
13 | "Mute": "Без звуку",
14 | "Unmuted": "Зі звуком",
15 | "Playback Rate": "Швидкість відтворення",
16 | "Subtitles": "Субтитри",
17 | "subtitles off": "Без субтитрів",
18 | "Captions": "Підписи",
19 | "captions off": "Без підписів",
20 | "Chapters": "Розділи",
21 | "You aborted the video playback": "Ви припинили відтворення відео",
22 | "A network error caused the video download to fail part-way.": "Помилка мережі викликала збій під час завантаження відео.",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "Неможливо завантажити відео через мережевий чи серверний збій або формат не підтримується.",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "Відтворення відео було припинено через пошкодження або у зв'язку з тим, що відео використовує функції, які не підтримуються вашим браузером.",
25 | "No compatible source was found for this video.": "Сумісні джерела для цього відео відсутні."
26 | });
--------------------------------------------------------------------------------
/client/js/videojs/lang/zh.js:
--------------------------------------------------------------------------------
1 | videojs.addLanguage("zh",{
2 | "Play": "播放",
3 | "Pause": "暂停",
4 | "Current Time": "当前时间",
5 | "Duration Time": "时长",
6 | "Remaining Time": "剩余时间",
7 | "Stream Type": "媒体流类型",
8 | "LIVE": "直播",
9 | "Loaded": "加载完毕",
10 | "Progress": "进度",
11 | "Fullscreen": "全屏",
12 | "Non-Fullscreen": "退出全屏",
13 | "Mute": "静音",
14 | "Unmuted": "取消静音",
15 | "Playback Rate": "播放码率",
16 | "Subtitles": "字幕",
17 | "subtitles off": "字幕关闭",
18 | "Captions": "内嵌字幕",
19 | "captions off": "内嵌字幕关闭",
20 | "Chapters": "节目段落",
21 | "You aborted the video playback": "视频播放被终止",
22 | "A network error caused the video download to fail part-way.": "网络错误导致视频下载中途失败。",
23 | "The video could not be loaded, either because the server or network failed or because the format is not supported.": "视频因格式不支持或者服务器或网络的问题无法加载。",
24 | "The video playback was aborted due to a corruption problem or because the video used features your browser did not support.": "由于视频文件损坏或是该视频使用了你的浏览器不支持的功能,播放终止。",
25 | "No compatible source was found for this video.": "无法找到此视频兼容的源。",
26 | "The video is encrypted and we do not have the keys to decrypt it.": "视频已加密,无法解密。"
27 | });
--------------------------------------------------------------------------------
/client/js/videojs/video-js.css:
--------------------------------------------------------------------------------
1 | /*!
2 | Video.js Default Styles (http://videojs.com)
3 | Version 4.11.2
4 | Create your own skin at http://designer.videojs.com
5 | */
6 | /* SKIN
7 | ================================================================================
8 | The main class name for all skin-specific styles. To make your own skin,
9 | replace all occurrences of 'vjs-default-skin' with a new name. Then add your new
10 | skin name to your video tag instead of the default skin.
11 | e.g.