API Docs for:
Show:

File: generic-playlist-movie.js

/*******************************************************************************
 * Copyright (c) 2017 Genialist Software Ltd.
 * All rights reserved.
 ******************************************************************************/

function pMoviePlaylistInstance() {
	var that = this, updatems = pDevice.isMobile()? 0 : 10000, max_size = 1, medias = new pMap(), current_id, m_preload_update = true;
	
	this.tracePrefix = 'MoviePlaylist';
	this.title = null;
	
	function f_isVisited(i_media) {
		return (i_media.play_count && i_media.play_count > 0);// || (i_media.play_time && i_media.play_time > 1000);
	}
	
	function f_visitedCookieName(u) {
		return 'v-'+pLocation.path(u).substring(url_prefix.length);
	}
	
	function f_sortMedias(a, b) { 
		var i_a = h_isHTTPURL(a.url), i_b = h_isHTTPURL(b.url);
		if ((i_a && i_b) || (!i_a && !i_b)) {
			return a.pos<b.pos? -1 : a.pos>b.pos? 1 : 0;
		}
		return i_a? 1 : -1;
	}
	
	this.setMaxSize = function(n) {
		max_size = parseInt(n);
	};
	this.unavailable = function() {
		for(var i=0 ; i<max_size ; i++) {
			if (medias.valueAt(i).medias == null)
				return true;
			if (medias.valueAt(i).unavailable === true)
				return true;
		}
		return false;
	};
	
	var m_cache;
	this.cache = function(p_url, p_media) {
		m_cache = m_cache || new pMap();
		m_cache.put(p_url, p_media);
	};
	this.getCached = function(p_url) {
		return m_cache? m_cache.getValue(p_url, null) : null;
	};
	
	this.getValue = function(p_request) {

		//*** REARRANGE REQUEST OBJECT
		if (!p_request) p_request = {};
		if (typeof p_request=="string") p_request = { url: p_request, m_available: true };
		if (!p_request.id) p_request.id = 'default';
		if (null==p_request.m_available) p_request.m_available = true;

		//*** RETRIEVE DATA
		var i_request = medias.getValue(p_request.id, null);
		if (!i_request)
			medias.put(p_request.id, i_request = p_request);

		return i_request;
	};
	this.getPlaying = function() {
		return current_id? that.getValue(current_id) : null;
	};
	this.canPlay = function(i_media) {
		if (/*i_media.unavailable ||*/ ((i_media.metadata_dvd || i_media.metadata_bluray) && (!getVLCPlugin() || !i_media.mrl_local)))
			return false;
		return true;
	};
	
	var preload_bacth = 0, preload_batch_done = 0, preloadAll_lst;
	this.preloadAll = function() {
		var a = '';
		
		//0.9.19
		if (!preloadAll_lst) {
			preloadAll_lst = true;
			document.addEventListener("xfindmetadata", this.preloadAll);
		}
		
		preload_batch = 0;
		medias.values().forEach(function(r, i) {
			r = that.getValue(r);
			
			if (!(r.preload === false) && !(r.preload_update === false) && !r.deleted) {
				preload_batch++;
				
				a = pURL.addBodyParameter(a, 'id'+i, r.id);
				a = pURL.addBodyParameter(a, 'a'+i, r.url + "&checkPlaySession=false&format=json&markAsPlayed=false" + (r.medias? "&sid="+r.medias[0].sid : ""));
			}
		});
		
		if (pString.v(a)) {
			preload_batch_done = 0;
			
			//if (null==i_request.m_available || i_request.m_available === true) {
			//	this.showAsAvailable(i_request);
			//}
			
			pHTTPRequest.invoke({ 
				url: pURL.addQueryParameter(null, "action", "multiple"), 
				method: 'POST',
				sync: false,
				body: a,
				headers: pHTTPRequest.headers_post,
				onreadystatechange: function(request) {
					var i_playlist = that;
	
					// not found
					if (request.status==404) {
						medias.values().forEach(function(r, i) {
							r = this.getValue(r);
							
							if (r.m_available === true) {
								i_playlist.showAsUnavailable(r);
								pElement.setInnerHTML('movie-play-'+r.id+'-debug', '<div class="unavailable">Unavailable</div>');
								pElement.setInnerHTML('episode-ep-'+r.id+'-menu', '');
								var m = pElement.x('episode-ep-'+r.id+'-menu');
								if (m) m.style.height = 'auto';
							}
							r.m_available = false;
						});
						if (updatems)
							pDocument.setTimeout(i_request.id, i_request.f_preload/*function(){ i_playlist.preload.call(i_playlist,  i_request); }*/, updatems);
	
						return;
					}
	
					//requires login
					if (request.status==200 && request.responseText.indexOf('<html')>=0 && !pDocument.componentIsShown('div-vlc')) {
						window.location.replace("/login?url="+encodeURI(pLocation.getPathAndQuery())+"&expired=true");
						return false;
					}
	
					// other errors
					if (request.status!=200 || request.responseText.indexOf('<html')>=0 && !pDocument.componentIsShown('div-vlc')) {
						pROSE.showErrorPage(request.responseText);
						return false;
					}
	
					var o =pJSON.parse(request.responseText);
					
					o.results.forEach(function(o) {
						i_playlist.preloadImpl(i_playlist, i_playlist.getValue({ id: o.id }), o.result);	
					});
					
				}
			});			
		}
	};
	
	this.preloadAllDone = function() {
		preload_batch_done++;
		if (preload_batch_done >= preload_batch) {
			if (medias.values().some(function(m) { return m.m_available === false; }))
				pDocument.setTimeout('movie-preload-batch', that.preloadAll, updatems);
			else
				pDocument.setTimeout('movie-preload-batch', that.preloadAll, updatems * 4);
		}
			
	};
	
	this.preload = function(p_request, batch) {

		var i_request = that.getValue(p_request);
		
		if (i_request.preload === false)
			return;

		i_request.preloadTimeout = null;
		i_request.f_preload = i_request.f_preload || function() { that.preload(i_request); };
		/*if (!i_request.f_preload)
			i_request.f_preload = function() { 
				this.playlist.preload.call(this.playlist, this.request); 
			}.bind({ playlist: this, request: i_request });*/

		//0.9.19
		if (!i_request.lst) {
			i_request.lst = true;
			document.addEventListener("xfindmetadata", i_request.f_preload);
		}
		
		if (i_request.deleted === true)
			return;
		if (!m_preload_update)
			return;

		if (batch || i_request.batch) {
			i_request.batch = true;
			pConsole.info(that, "do not preload (buffer): " + p_request.id);
			return;
		}
		
		//pDocument.hide('movie-play');
		if (null==i_request.m_available || i_request.m_available === true) {
			that.showAsAvailable(i_request);
		}

		var i_url = pURL.addQueryParameter(i_request.url, [ "checkPlaySession", 0, "format", "json", "markAsPlayed", 0 ]);
		//pConsole.info(that, "Preload movie " + pDate.toLocaleString(new Date()) + ": " + i_request.id + ": " + i_url);
		pHTTPRequest.get(i_url, function(request) {

			var i_playlist = this.playlist;
			var i_request = this.i_request;

			//pConsole.info(that, pJSON.pretty(request.responseText));
			//var request = p_event.target;
			//if (request.readyState === 4) {// When response is complete

				// not found
				if (request.status==404) {
					if (i_request.m_available === true) {
						i_playlist.showAsUnavailable(i_request);
						pElement.setInnerHTML('movie-play-'+i_request.id+'-debug', '<div class="unavailable">Unavailable</div>');
						pElement.setInnerHTML('episode-ep-'+i_request.id+'-menu', '');
						var m = pElement.x('episode-ep-'+i_request.id+'-menu');
						if (m) m.style.height = 'auto';
					}
					i_request.m_available = false;
					if (updatems)
						pDocument.setTimeout(i_request.id, i_request.f_preload, updatems);

					return;
				}

				//requires login
				if (request.status==200 && request.responseText.indexOf('<html')>=0 && !pDocument.componentIsShown('div-vlc')) {
					window.location.replace("/login?url="+encodeURI(pLocation.getPathAndQuery())+"&expired=true");
					return false;
				}

				// other errors
				if (request.status!=200 || request.responseText.indexOf('<html')>=0 && !pDocument.componentIsShown('div-vlc')) {
					pROSE.showErrorPage(request.responseText);
					return false;
				}

				i_playlist.preloadImpl(i_playlist, i_request, request.responseText);	
			//}

		}.bind({ playlist: this, i_request: i_request }), false, this);
	};
	
	this.preloadImpl = function(i_playlist, i_request, responseText) {
		
		pConsole.debug(that, 'Preload... Response: ' + responseText);
		var i_medias = pJSON.parse(responseText).files;
		//alert(pJSON.pretty(request.responseText));
		
		//*** MODIFY
		var i_canplay = false; // at least one can play
		i_medias.forEach(function(m, i) {
			if (m.metadata_provider == '(Radio)') m.play_updated_url = null;
			m.pos = i;
			
			if (i_request.title)
				m.title = ((m.length>1)? ''+(i+1)+'/'+m.length+ ' - ':'') + i_request.title;
			
			m.canplay = that.canPlay(m);
			i_canplay = i_canplay || m.canplay;
			
			if (m.alt) {
				m.alt.forEach(function(a, j) {
					a.pos = j;
					
					if (i_request.title) a.title = m.title;
					
					a.canplay = that.canPlay(a);
					i_canplay = i_canplay || a.canplay;
				});
				if (m.alt.length>1)
					m.alt = m.alt.sort(f_sortMedias);
			}
		});
		i_request.medias = i_medias.sort(f_sortMedias);
		

		//*** SORT ALTS
		/*i_medias.forEach(function(m) {
			if (m.alt && m.alt.length>0) {
				m.alt.forEach(function(m, i) { m.pos = i; });
				m.alt = m.alt.sort(f_sortMedias);
			}
		});*/
		
		//if (i_medias.length > 0 && i_medias[0].play_count && i_medias[0].play_count > 0) {
		//	pElement.addClassName('movie-play-'+i_request.id+'-button', "play-visited");
		//}

		//*** COPY TITLE INTO MEDIAS
		/*if (i_request.title)
			i_medias.forEach(function(m, i) {
				m.title = ((m.length>1)? ''+(i+1)+'/'+m.length+ ' - ':'') + i_request.title;
				if (m.alt)
					m.alt.forEach(function(a) {
						a.title = m.title;
					});
			});*/

		//*** CAN PLAY
		/*var i_canplay = false; // at least one can play
		i_medias.forEach(function(m) {
			m.canplay = that.canPlay(m);
			i_canplay = i_canplay || m.canplay;
			if (m.alt)
				m.alt.forEach(function(a) {
					a.canplay = that.canPlay(a);
					i_canplay = i_canplay || a.canplay;
				});
		});*/

		var i_details = /*'<div>'+pJSON.pretty(request.responseText)+'</div>'+*/mediaDetails(i_request.id, i_medias, i_request);
		if (!i_request.details || i_request.details != i_details)
			pElement.setInnerHTML('movie-play-'+i_request.id+'-debug', i_request.details = i_details);

		var x = pElement.x('movie-play-'+i_request.id+'-menu');
		if (pDocument.isShownSmooth(x))
			pDocument.setSmoothAutoHeight(x);
		else if (x && x.style.height!='0px')
			x.style.height = 'auto';
			
		if (i_request.id=='default' && that.resizeDefaultMenu)
			if (pDocument.isShown('movie-play-default-menu'))
				that.resizeDefaultMenu();

		for(var i=0 ; i<i_medias.length ; i++) {
			
			var i_unavailable = i_medias[i].unavailable || !i_medias[i].canplay; // all of them unavailable
			if (i_medias[i].alt)
				i_medias[i].alt.forEach(function(a) {
					i_unavailable = i_unavailable && (a.unavailable || !a.canplay); 
				});
			
			if (!i_canplay || i_unavailable) {
				if (i_request.m_available === true) {
					i_playlist.showAsUnavailable(i_request);
				}
				i_request.m_available = false;
				if (updatems) {
					if (i_request.batch)
						i_playlist.preloadAllDone();
					else
						pDocument.setTimeout(i_request.id, i_request.f_preload, updatems);
				}
				return;
			}
		}

		if (i_request.m_available === false)
			i_playlist.showAsUnavailable(i_request);
		
		i_request.m_available = true;
		i_playlist.showAsAvailable(i_request);
		if (updatems) {
			if (i_request.batch)
				i_playlist.preloadAllDone();
			else
				pDocument.setTimeout(i_request.id, i_request.f_preload, updatems * 4);
		}
		
		//*** SHOW AS VISITED...
		var i_done = false;
		for(var i=0 ; i<i_medias.length ; i++) {
			if (f_isVisited(i_medias[i])===true) {
				i_playlist.showAsVisited(i_request);
				i_done = true;
				break;
			}
			if (i_medias[i].alt)
				for(var j=0 ; j<i_medias[i].alt ; j++)
					if (f_isVisited(i_medias[i].alt[j])===true) {
						i_playlist.showAsVisited(i_request);
						i_done = true;
						break;
					}

			if (i_done === true) {
				break;
			}
		}
		
		if (i_request.play) {
			var i_play = i_request.play;
			i_request.play = null;
			
			i_playlist.play(i_play.request, i_play.askResume, i_play.media);
			return;
		}
	};
	
	this.showAsAvailable = function(p_request) {
		p_request = that.getValue(p_request);

		pDocument.show('movie-play-'+p_request.id, 'auto');
		pDocument.show(pElement.c('toolbar-play'), 'auto');
		
		pDocument.show('tvepisode-'+p_request.id+'-container-title');
		pDocument.hide('tvepisode-'+p_request.id+'-container-title-unavailable');
		
		pDocument.hide('movie-play-'+p_request.id+'-unavailable');
		pDocument.hide('movie-play-'+p_request.id+'-unavailable2');
		pElement.removeClassName(pElement.c('container-movie-play-'+p_request.id+'-unavailable'), 'movie-unavailable');

		var a = false;
		if (p_request.medias) {
			a = true;
			p_request.medias.forEach(function(m) {
				if (m.provided === true) a = false;
				if (m.alt)
					m.alt.forEach(function(a) {
						if (a.provided === true) a = false;
					});
			});
		}
		
		pApplicationUI.showToolsConvertAll(null, a);//pElement.removeClassName('toolbar-convert', 'unavailable');
	};
	this.showAsUnavailable = function(p_request) {
		p_request = this.getValue(p_request);

		pDocument.hide('movie-play-'+p_request.id);
		pDocument.hide(pElement.c('toolbar-play'));

		pDocument.hide('tvepisode-'+p_request.id+'-container-title');
		pDocument.show('tvepisode-'+p_request.id+'-container-title-unavailable');
		
		pDocument.show('movie-play-'+p_request.id+'-unavailable');
		pDocument.show('movie-play-'+p_request.id+'-unavailable2');
		pElement.addClassName(pElement.c('container-movie-play-'+p_request.id+'-unavailable'), 'movie-unavailable');

		pApplicationUI.showToolsConvertAll(null, false);//pElement.addClassName('toolbar-convert', 'unavailable');
	};
	this.playURL = function(m) {
		
		if (pConsole.debugging())
			alert(m? 'Check Media can play on other web-site:\n' + pJSON.pretty(m) : 'no media (m is null)');
		
		if (pMedia.externalPlay(m)) {
			if (pConsole.debugging())
				alert('Going to other web-site:\n' + m.url);
				
			window.open(m.url, '_blank');
			return true;
		}
	};
	this.createMediaFromYTURL = function(u, title) {
		var u = u.split(';'), n = u.length>1? u[1] : null;
		u = u[0];
		if (u.startsWith('url:'))
			u = u.substring('url:'.length);
		if (n && n.startsWith('name:'))
			n = n.substring('name:'.length);
		
		return { metadata_provider: 'youtube', url: u, title: n || title };
	};
	this.playTrailer = function(u, title) {
		var m = that.createMediaFromYTURL(u, title);
		
		return that.play({ id: m.url, preload: false, medias: [ m ], title: m.title }, false, null, false, true);
	};
	
	var trailers, registered_open_close;
	this.play = function(p_request, p_askResume, p_media, p_static, p_notrailers) {

		try {
			var i_request = this.getValue(p_request);

			//alert("request: " + pJSON.pretty(JSON.stringify(i_request)));
			//alert("media: " + ((p_media)? pJSON.pretty(JSON.stringify(p_media)) : 'null'));

			if (!i_request.medias) {
				pDocument.wait();
				
				i_request.play = { request: p_request, askResume: p_askResume, media: p_media};
				return;
			}
			
			//*** PREFER STREAMING
			if (!p_media && pPlaylistUtil.OPTION_PREFER_STREAMING)
				if (i_request.medias.find(function(m) {	return that.playURL(m); }))
					return;
			
			//*** FIND ALTERNATIVE MEDIAS
			if (!p_media && i_request.medias.some(function(i_media) { return i_media.canplay === false || i_media.unavailable; })) {
				var i_play = i_request.medias;
				for(var i=0 ; i<i_request.medias.length ; i++) {
					var i_media = i_request.medias[i];
					if ((i_media.canplay === false || i_media.unavailable) && i_media.alt)
						for(var j=0 ; j<i_media.alt.length ; j++) {
							var i_alt = i_media.alt[j];
							if (i_alt.canplay === true && !i_alt.unavailable) {
								i_play[i] = that.getCached(i_alt.doc_url);
								break;
							}
						};
				};

				/*if (i_request.medias[0].alt)
					for(var i=0 ; i<i_request.medias[0].alt.length ; i++) {
						var i_alt = i_request.medias[0].alt[i];
						if (i_alt.canplay === true)
							return this.play({ id: i_request.id }, p_askResume, [ that.getCached(i_alt.doc_url) ]);
					};*/

				return this.play({ id: i_request.id }, p_askResume, i_play);
			}

			if (i_request.m_available === false) {
				pConsole.info(that, 'Play ' + i_request.url + ((i_request.medias)? ' (preloaded)':'') + ': Unavailable...');
				return;
			}
			
			//*** PLAY URL
			if (p_media)
				if (that.playURL(p_media[0]))
					return;
			if (i_request.medias)
				if (that.playURL(i_request.medias[0]))
					return;

			//*** SHOW CAPTURE BUTTONS
			if (!pDevice.isSmallScreen()) {
				pElement.setInnerHTML('v0-artwork-text', pDocument.getStyleValue('btn-capture-artwork'));
				pDocument.show('v0-artwork', 'auto');
			}
			else
				pDocument.hide('v0-artwork');

			//*** STOP UPDATING UNAVAILABLE STATUS...
			m_preload_update = false;
			for(var i=0 ; i<medias.length ; i++) {
				var i_media = medias.valueAt(i);
				pDocument.clearTimeout(i_media.id);
			}

			//*** LOG...
			pConsole.info(that, 'Play ' + ((p_media)? p_media[0].doc_url : ((i_request.medias)? i_request.medias[0].doc_url : i_request.url)) + ((p_media || i_request.medias)? ' (preloaded)':''));
			//pConsole.info(that, 'Play ' + ((p_media)? p_media[0].mrl_local : ((i_request.medias)? i_request.medias[0].mrl_local : i_request.url)) + ((p_media || i_request.medias)? ' (preloaded)':''));

			current_id = i_request.id;

			//*** START
			var title = pApplicationUI.episode.getTitle('tvepisode-'+i_request.id+'-container-title') || i_request.title || that.title;
			if (!p_static) {
				
				var r = (null!=p_askResume)? p_askResume : i_request.askResume, m = p_media || i_request.medias;
				if (m) {
					var cr = m_vlc.canResume(m.forEach? m[0] : m, true), f_open = function() { m_vlc.open(m, r, title); };
				
					if (pPlaylistUtil.OPTION_MOVIE_TRAILERS && !p_notrailers && !cr) {
						
						if (trailers)
							m_vlc.open(trailers.concat(m), false, title);
						else {
							pDocument.wait('Searching for Movie Trailers...');
							pHTTPRequest.invoke({ url: '?action=get-trailers&v='+Math.random(), timeout: 20000 }).then(function(r) {
								var o = pJSON.parse(r.responseText);
								if (pString.v(o.uris)) {
									var u = o.uris.split('|').filter(pString.v);
									
									trailers = u.map(that.createMediaFromYTURL);
									
									//pDocument.stop
									m_vlc.open(trailers.concat(m), false, title);
								}
								else
									f_open();
							}, f_open);
						}
					}
					else
						f_open();
				}
				else
					m_vlc.open(i_request.url + "&format=json&markAsPlayed=false&dummy=foo", r, title);
			}
			else
				pNoteUI.notesDialog('help-optimize-videos').then(function() {
					m_vlc.open(
							p_media || (i_request.medias || i_request.url + "&format=json&markAsPlayed=false&dummy=foo"),
							(null!=p_askResume)? p_askResume : i_request.askResume, title, null, true);
				});

			if (!p_static) {
				if (i_request.medias)
					this.incr(i_request);
				else
					this.mark(i_request);
			}
			
			if (!registered_open_close) {
				registered_open_close = true;

				m_vlc.addEventListener("ended", that.m_tv_func_ended);
				m_vlc.addEventListener("unhandled-next", that.m_tv_func_next);
				m_vlc.addEventListener("unhandled-previous", that.m_tv_func_previous);
				m_vlc.addEventListener("close-after", function(){ m_preload_update = true; });
			}
		}
		catch (exception) {
			alert(exception + '\n' + exception.stack);
		}
	};
	this.m_tv_func_previous = function() {
		pConsole.debug(that, "tv_func_previous");

		if (that.all === true) {
			var i_next = medias.previousKey(current_id);
			if (!i_next && that.all_loop === true)
				i_next = medias.keyAt(medias.length-1);
			
			if (i_next) {
				pConsole.debug(that, 'Previous episode: ' + i_next);
				var r = that.getValue({ id: i_next });
				if (r) {
					pConsole.info(that, "Playing previous episode ("+i_next+")...");
	
					that.play(r, false);
				}
				return;
			}
		}
	};
	this.m_tv_func_next = function() {
		pConsole.debug(that, "tv_func_next");

		if (that.all === true) {
			var i_next = medias.nextKey(current_id);
			if (!i_next && that.all_loop === true)
				i_next = medias.keyAt(0);
			
			if (i_next) {
				pConsole.debug(that, 'Next episode: ' + i_next);
				var r = that.getValue({ id: i_next });
				if (r) {
					pConsole.info(that, "Playing next episode ("+i_next+")...");
	
					that.play(r, false);
					return true;
				}
			}
		}
	};
	this.m_tv_func_ended = function() {
		pConsole.debug(that, "tv_func_ended");

		if (!that.m_tv_func_next())
			current_id = null;
		
	};

	this.incr = function(r) {
		that.mark(r);

		r = that.getValue(r);

		if (r.url_incr)
			pHTTPRequest.post(r.url_incr);
	};
	this.mark = function(r) {
		r = that.getValue(r);

		if (r.url_doc)
			pCookieManager.set(f_visitedCookieName(r.url_doc), '1');
		r.visited = true;
		that.showAsVisited(r);
	};
	this.unmark = function(r) {
		r = that.getValue(r);

		if (r.url_doc)
			pCookieManager.remove(f_visitedCookieName(r.url_doc));
		r.visited = false;
		that.showAsNotVisited(r);
	};
	this.reset = function(r) {
		that.unmark(r);

		r = that.getValue(r);

		if (r.url_reset)
			pHTTPRequest.post(r.url_reset);
	};
	this.showAsVisited = function(r) {
		r = that.getValue(r);
		
		//0.9.19
		if (r.medias && !r.medias.some(function(m) { return m.play_updated_url }))
			return;

		pElement.addClassName("movie-play-"+r.id+"-button", "play-visited");
		pElement.addClassName("movie-play-"+r.id+"-button-unavailable", "play-visited");

		pDocument.hide("movie-play-"+r.id+"-incr");
		pDocument.show("movie-play-"+r.id+"-reset", "inline-block");
	};
	this.showAsNotVisited = function(r) {
		r = that.getValue(r);

		//0.9.19
		if (r.medias && !r.medias.some(function(m) { return m.play_updated_url }))
			return;
		
		pElement.removeClassName("movie-play-"+r.id+"-button", "play-visited");
		pElement.removeClassName("movie-play-"+r.id+"-button-unavailable", "play-visited");

		pDocument.show("movie-play-"+r.id+"-incr", "inline-block");
		pDocument.hide("movie-play-"+r.id+"-reset");
	};

	// "all" property
	var m_all = (pCookieManager.getCookie('playlist-all-episodes') === 'false')? false : true;
	Object.defineProperty(this, "all", { get: function() { return m_all; }, set: function(v) { if (typeof v == "boolean") m_all = v; }});

	//*** ADD KEY HANDLERS
	pDocumenti.addOnKeyDown(function(event) {
		if (!m_vlc)
			return;

		var key = ('which' in event)? event.which : event.keyCode;
		pConsole.debug(this, "movie key :" + key);
		if (key == 32) {
			if (m_vlc.medias.length==0) {
				var i_request = that.getValue({ id: medias.keyAt(0)});
				if (i_request) {
				//if (that.m_available === true) {
				//if (medias.length>0) {//null!=that.m_preloaded_medias || null!=that.m_preloaded_url) {
					that.play(i_request);
					return true;
				}
			}
		}
		if (key >= 97 && key <= 105) { //1 to 9if (e.keyCode <=
			var i = key -96;
			if (m_vlc.medias.length==0) {
				var i_request = that.getValue({ id:'0'+i });
				if (i_request) {
				//if (that.m_available === true) {
				//if (medias.length>0) {//if (null!=that.m_preloaded_medias || null!=that.m_preloaded_url) {
					that.play(i_request);
					return true;
				}
			}
		}
	});

	// "preload_update" property
	Object.defineProperty(this, "preload_update", { get: function() { return m_preload_update; }, set: function(v) {
		if (typeof value == "boolean") {
			var i_old = m_preload_update;
			m_preload_update = v;
			if (i_old === false && v === true)
				medias.values().forEach(this.preload);
				//for(var i=0 ; i<medias.length ; i++)
				//	preload({ id: medias.keyAt(i) });//that.m_preloaded_url);
		}
	}});

	this.clear = function() {
		var i_update = m_preload_update;

		m_preload_update = false;

		for(var i=0 ; i<medias.length ; i++)
			medias.valueAt(i).deleted = true;

		medias.clear();
		m_preload_update = i_update;
	};
};

var pMoviePlaylist = new pMoviePlaylistInstance();

/******************************************************************************/
/***  PAGE INIT  **************************************************************/
/******************************************************************************/

var m_vlc = null;
var m_vlc_langs = null;

/******************************************************************************/
/******************************************************************************/
/******************************************************************************/

/*

[ {
		"request_url": "/zrose/8e76e084-eac4-460c-9b95-06abfbf26291/tvshows.seasons/435?play&ep=01&format=json&markAsPlayed=false",
		"url": "/zrose/8e76e084-eac4-460c-9b95-06abfbf26291/play/0a3d005b-e4bd-468c-94f3-da2ecb058d46",
		"mime": "video/x-matroska",
		"url_transcode": "/zrose/8e76e084-eac4-460c-9b95-06abfbf26291/play/0a3d005b-e4bd-468c-94f3-da2ecb058d46/index.m3u8",
		"play_count": 0,
		"play_time": 3520,
		"play_updated_url": "/zrose/8e76e084-eac4-460c-9b95-06abfbf26291/tvshows.medias/5445",
		"play_ended_url": "/zrose/8e76e084-eac4-460c-9b95-06abfbf26291/play/0a3d005b-e4bd-468c-94f3-da2ecb058d46/ended",
		"mrl_local": "file:///C%3A%2FManga%2F%3DSeries%2F%3DG%2FGunparade%20March%2FGunparade%20March%20%23%20Movies%2FGunparade%20March%20%23%20Season%201%2FGunparade%20March%20%23%201.01%20-%20The%20Visitor.mkv",
		"width": 640,
		"height": 480,
		"ms": 1416000,
		"hasAudio": true,
		"hasMusic": true,
		"hasVideo": true,
		"metadata_bpm": "", "metadata_bitrate": 0, "metadata_bitrate_video": 0, "metadata_bluray": "false", "metadata_channels": "6", "metadata_dimension": "null",
		"metadata_dvd": "false",
		"metadata_encodingType": "", "metadata_video_fhd": "false",
		"metadata_format": "A_AAC/MPEG4/LC/SBR",
		"metadata_frameRate": "23.976",
		"metadata_hard_subtitles": "false",
		"metadata_video_hd": "false", "metadata_lang": "english|japanese", "metadata_lang_subtitles": "English",
		"metadata_sampleRate": "44.1 KHz / 22.05 KHz", "metadata_sampleRate_video": "", "metadata_provider": "(Unknown)",
		"metadata_tracks": "
		id:0,lang:en,type:v,def:1,for:0,name:null|
		id:1,lang:en,type:a,def:1,for:0,name:null|
		id:2,lang:ja,type:a,def:1,for:0,name:null|
		id:3,lang:en,type:s,def:1,for:0,name:null|
		id:4,lang:en,type:s,def:1,for:0,name:null", "metadata_chapters": [] } ]
*/

function pFileDetailsInstance() {
	this.i_audio = 'Audio';
	this.i_video = 'Video';
	this.i_subtitles = 'SubTitles';
	this.i_unknown = 'Unknown';

	this.i_lang = 'Language';
	this.i_codec = 'Codec';
	this.i_stereo = 'Stereo';
	this.i_mono = 'Mono';
	this.i_channels = 'Channels';
	this.i_default = 'Default';
	this.i_forced = 'Forced';
};

var pFileDetails = new pFileDetailsInstance();

var i_mime_icons = new pMap([
	//"video/x-matroska", "mov",
	"video/mpeg", "mpg",
	//"video/mpeg", "mpeg",
	//"vcd",
	"video/mp4", "mp4",
	//"mp2",
	"video/quicktime", "mov",
	"video/x-mp4", "m4v",
	"video/mp4", "m4v",
	//"m4p",
	//"m4b",
	"audio/mp4", "m4a",
	//"iso",
	"video/flv", "flv",
	"video/x-flv", "flv",
	"video/divx", "divx",
	//"cda",
	//"amr",
	//"aiff",
	//"aif",
	"audio/3gpp", "3gp",
	"video/3gpp", "3gp",
	"audio/wav", "wav",
	"audio/x-wav", "wav",
	"audio/x-ms-wma", "wma",
	"video/x-ms-wmv", "wmv"
]);

function mediaDetails(p_request_id, p_medias, p_request) {

	var h = '';

	p_medias.forEach(function(m, i) {
		pMoviePlaylist.cache(m.doc_url, m);
		
		//*** START and END
		if (m.start_time!=null && m.stop_time!=null)
			h += '<div class="media-part"><div class="media-part-title">Part ' + (i+1) + '/' + p_medias.length + ': ' + (m.start_time<=0? 'Start':pTime.display(m.start_time)) + ' to ' + pTime.display(m.stop_time) + ' of File(s):</div>';
		else
			h += '<div class="media-part"><div class="media-part-title">Part ' + (i+1) + '/' + p_medias.length + ' File(s):</div>';
		
		h += mediaDetail(p_request_id, m, false, p_request);
		if (m.alt)
			m.alt.forEach(function(a) {
				pMoviePlaylist.cache(a.doc_url, a);
				h += mediaDetail(p_request_id, a, false, p_request);
			});
		h += '</div>';
	});
	return h;
}

function trackDetails(t, i_media, ts) {
	var h = '<tr>';
		
	h += '<td class="media-track-field media-track-type">'
	if (t.type == "a")
		h += pFileDetails.i_audio;
	else if (t.type == "v")
		h += pFileDetails.i_video;
	else if (t.type == "s") {
		//if (t.filename)
		//	h += '<a href="javascript:void(pMediaLibrary.getFileMetadata(\''+ i_media.doc_url+'\', \''+t.filename+'\'))">'+pFileDetails.i_subtitles+'</a>';
		//else
			h += pFileDetails.i_subtitles;
	}
	else
		h += pFileDetails.i_unknown;
	h += '</td>';

	h += '<td class="media-track-field media-track-lang lang">';
	if (t.metadata_lang) h += pString.encodeHTML(pLang.display(t.metadata_lang));
	h += '</td>';

	h += '<td class="media-track-field media-track-codec">';
	if (t.metadata_format) {
		if (t.type == 'a') h += pString.substring_after(t.metadata_format, 'A_');
		if (t.type == 'v') h += pString.substring_after(t.metadata_format, 'V_');
		if (t.type == 's') h += pString.substring_after(t.metadata_format, 'S_');
		
		//h += t.type=='a'? pString.substring_after(t.metadata_format, 'A_') : pString.substring_after(t.metadata_format, 'V_'); 
		if (t.type == "a") {
			if (t.metadata_bitrate && t.metadata_bitrate.indexOf('0 ')!=0 && t.metadata_bitrate.indexOf('~')!=0) {
				/*if (i_media.metadata_bitrate && i_media.metadata_bitrate>0) {
					var d = pMetadata.rate(i_media.metadata_bitrate);
					var t = pMetadata.rate(t.metadata_bitrate);
					if (d!=t) h += ' ' + t;
				}
				else*/
					h += ' ' + pString.encodeHTML(pMetadata.rate(t.metadata_bitrate));
			}
		}
	}
	h += '</td>';

	h += '<td class="media-track-field media-track-channels">';
	if (t.type == "a") {
		if (parseInt(t.metadata_channels) === 2)
			h += pFileDetails.i_stereo;
		else if (parseInt(t.metadata_channels) === 1)
			h += pFileDetails.i_mono;
		else if (t.metadata_channels)
			h += 'Channels: '+pString.encodeHTML(t.metadata_channels);
	}
	h += '</td>';

	h += '<td class="media-track-field media-track-default">';
	if (t.vdefault === true) h += pFileDetails.i_default; //IE9
	h += '</td>';

	h += '<td class="media-track-field media-track-forced">';
	if (t.forced === true) h += pFileDetails.i_forced;
	h += '</td>';

	h += '<td class="media-track-field media-track-name">';
	if (t.name && t.name!="null") {
		if (t.filename)
			h += '<span class="link" onclick="pMediaLibrary.getFileMetadata(\''+ i_media.doc_url+'\', \''+t.filename+'\')">'+ pString.encodeHTML(pTrackListUtil.longName(t)) + '</span>';
		else
			h += pString.encodeHTML(pTrackListUtil.longName(t, ts));
	}
	h += '</td>';
	
	h += '<td class="media-track-field media-track-support">';
	if (pTrackListUtil.isSubtitle(t) && !pTrackListUtil.isSupportedSubtitle(t)) h += '<span class="warning">NO</span>'; else h += ' Yes';
	h += '</td>';

	return h + '</tr>';
}

function mediaDetail(p_request_id, i_media, p_notoolbar, p_request, f_play) {

	var i_uid = ''+Math.random();
	if (p_request) objects.put(i_uid+'.f_preload', p_request.f_preload);
	
	var h = '<div class="media-file">', i_lid = i_media.doc_url? pMediaLibrary.getLIDfromURL(i_media.doc_url) : null, i_id = i_media.doc_url? pMediaLibrary.getIDfromURL(i_media.doc_url) : null;

	h += '<div class="media-file-header">';

	var i_img = '<div class="media-file-field media-file-thumbnail">';
	if (i_media.metadata_thumbnail_url)
		i_img += '<a id="artwork-link-'+i_lid+'-'+i_id+'" href=\"'+i_media.metadata_thumbnail_url+'\" target="_blank"><img id="artwork-'+i_lid+'-'+i_id+'" src=\"'+i_media.metadata_thumbnail_url+'\"/></a>';
	//else
		//i_img += '<img src=\"'+pGenericList.getListThumbnail(pMediaLibrary.getLIDfromURL(i_media.doc_url))+'\"/>';
	i_img += '</div>';
	
	if (i_media.metadata_dvd) {
		h += '<div class="media-file-field media-file-icon dvd"><!----></div>';
		h += i_img;
		h += '<div class="media-file-field media-file-name">DVD (requires VLC plugin)</div>';
	}
	else if (i_media.metadata_bluray) {
		h += '<div class="media-file-field media-file-icon bluray"><!----></div>';
		h += i_img;
		h += '<div class="media-file-field media-file-name">Blu-ray (requires VLC plugin)</div>';
	}
	else if (i_media.mime && i_media.mime != 'text/plain') {
		var m = i_media.mime;// || 'text/plain';

		h += '<div class="media-file-field media-file-icon">';
		h += '<img src="/resources/html/images/16x16/file_extension_'+ i_mime_icons.getValue(m, 'mov')+'.png" ondragstart="pDrag.setURL(event)" attr-url="'+i_media.doc_url+'"/></div>';
		h += i_img;
		h += '<div class="media-file-field media-file-name"><span class="mff-label">Type:</span><span class="mff-value">' + pString.encodeHTML(m) + '</span></div>';
	}

	if (i_media.ms) {
		h += '<div class="media-file-field media-file-duration"><span class="mff-label">Runtime:</span>';
		h += '<span class="mff-value duration">' + pString.encodeHTML(pTime.display(i_media.ms)) + '</span></div>';
	}

	if (i_media.hasVideo != false && i_media.width && i_media.height) {
		h += '<div class="media-file-field media-file-dimension"><span class="mff-label">Dimensions:</span>';
		
		var hd = '', w = i_media.width, hh = i_media.height;
		if (w>=1280 && hh>=720) hd = ' (HD)';
		if (w>=1920 && hh>=1080) hd = ' (Full HD)';

		if (w>=3840 && hh>=2160) hd = ' (4K)';
		if (w>=7680 && hh>=4320) hd = ' (8K)';
		
		h += '<span class="mff-value">'+pString.encodeHTML(w) + ' x ' + pString.encodeHTML(hh) + hd + '</span></div>';
	}

	if (i_media.metadata_bitrate && i_media.metadata_bitrate>0) {
		h += '<div class="media-file-field media-file-bitrate"><span class="mff-label">Bitrate (Audio):</span><span class="mff-value">';
		h += pString.encodeHTML(pMetadata.rate(i_media.metadata_bitrate)) + '</span></div>';
	}

	if (i_media.metadata_bitrate_video && i_media.metadata_bitrate_video>0) {
		h += '<div class="media-file-field media-file-bitrate"><span class="mff-label">Bitrate (Video):</span><span class="mff-value">';
		h += pString.encodeHTML(pMetadata.rate(i_media.metadata_bitrate_video)) + '</span></div>';
	}
	
	if (i_media.chapters && i_media.chapters.length>0)
		h += '<div class="media-file-field media-file-bitrate"><span class="mff-label">Chapters:</span><span class="mff-value">Yes</span></div>';

	if (i_media.metadata_provider && i_media.metadata_provider!='(Unknown)') {
		h += '<div class="media-file-field media-file-provider"><span class="mff-label">Provider:</span>';
		h += '<span class="mff-value">'+pString.encodeHTML(i_media.metadata_provider) + '</span></div>'; //TODO: protect against injection...
	}

	//*** START and END
	if (i_media.start_time!=null && i_media.stop_time!=null) {
		h += '<div class="media-file-field media-file-fragment">';
		h += '<span class="mff-label">Start:</span>';
		h += '<span class="mff-value">'+pTime.display(i_media.start_time) + '</span></div>'; //TODO: protect against injection...

		h += '<div class="media-file-field media-file-fragment">';
		h += '<span class="mff-label">End:</span>';
		h += '<span class="mff-value">'+pTime.display(i_media.stop_time) + '</span></div>'; //TODO: protect against injection...
	}

	h += '<div class="media-file-field media-file-last"><!-- --></div>';
	h += '</div>'; //end of header...
	
	//*** TRACKS
	var i_tracks = pTrackListUtil.tracks(i_media);
	if (i_tracks.length>0) {
		h += '<div class="media-file-field media-file-tracks">';
		h += '<div class="media-file-field media-file-tracks-list">';

		h += '<table><caption class="media-file-field media-file-tracks-header">Tracks</caption><tr><th class="th-type">Type</th><th>'+pFileDetails.i_lang+'</th><th class="th-codec">'+pFileDetails.i_codec+'<th class="th-audio">Audio</th>';
		h += '<th class="th-default">Default</th><th class="th-forced">Forced</th><th class="th-name">Name</th><th class="th-support">Supported</th></tr>';
		i_tracks.forEach(function(t) {
			h += trackDetails(t, i_media, i_tracks);
		});
		(i_media.subtitle_files || []).forEach(function(f) {
			i_tracks = pTrackListUtil.tracks(i_media.subtitle_files);
			i_tracks.forEach(function(t) {
				h += trackDetails(t, i_media);
			});
		});
		
		if (i_media.metadata_dvd)
			h += '<tr><td colspan="20" class="media-track-field media-track-support">Cannot play this media...</td></tr>';
		else if (i_media.metadata_bluray)
				h += '<tr><td colspan="20" class="media-track-field media-track-support">Cannot play this media...</td></tr>';
		else {
			var r = m_vlc.check(i_media);
			if (r) {
				h += '<tr><td colspan="20" class="media-track-field media-track-support">';
				if (r.url)
					h += 'Media will be transcoded...'
				else
					h += 'Media will be played directly...'
				if (r.reason.length>0) {
					h += ' (';
					r.reason.forEach(function(r, i) { h+= ((i>0)? ', ' : '') + r; });
					h += ')';
				}
				h += '</td></tr>';
			}
		}
		
		h += '</table>';
		h += '</div></div>';
	}

	//*** TOOLBAR
	if (!p_notoolbar) {
		var i_id = Math.random();

		h += '<div class="media-file-menu"><div class="toolbar" id="'+i_id+'-toolbar">';

		if (!i_media.unavailable) {
			if (i_media.canplay === false) {
				h += '<div class="toolbar-item warning">Cannot play this media on this device...</div>';
			}
			else if (i_media.onclick_play) {
				//objects.put(i_id, i_media.onclick_play);
				
				h += pApplicationUI.toolbarItem('play', i_media.onclick_play); //TODO: cannot work...
				//h += '<div class="toolbar-item toolbar-play link" onclick="'++'">';
				//h += pResources.resources.toolbar.play+'</div>';
			}
			else if (f_play) {
				objects.put(i_id, f_play);
				
				h += pApplicationUI.toolbarItem('play', 'objects.getValue(\''+i_id+'\').call()');
				//h += '<div class="toolbar-item toolbar-play link" onclick="">';
				//h += pResources.resources.toolbar.play+'</div>';
			}
			else {
				h += pApplicationUI.toolbarItem('play', 'pMoviePlaylist.play({ id: \''+p_request_id+'\' }, true, [ pMoviePlaylist.getCached(\''+i_media.doc_url+'\') ])');
				//h += '<div class="toolbar-item toolbar-play link" onclick="">';
				//h += pResources.resources.toolbar.play+'</div>';
			}
		}
		else
			h += '<div class="toolbar-item warning">Cannot play this media (file unavailable)...</div>';

		if (pResources.get('admin') == 'true') {

			h += pApplicationUI.toolbarItem('remove', 'pMediaLibrary.remove({ url: \''+i_media.doc_url+'\', fdeleted: objects.getValue(\''+i_uid+'.f_preload\')})');
			//h += '<div class="toolbar-item toolbar-remove link" onclick="';
			//h += '">'+pResources.resources.toolbar.remove+'</div>';

			if (!i_media.unavailable) {
				if (i_media.provided == true && i_media.url) {
					h += pApplicationUI.toolbarItem('reimport', 'pMediaLibrary.addURLToLibrary(null, \''+i_media.url+'\', \''+i_lid+'\', \''+pMediaLibrary.getIDfromURL(i_media.doc_url)+'\')');
				}
				else {
					h += pApplicationUI.toolbarItem('reimport', 'pMediaLibrary.reImport({ url: \''+i_media.doc_url+'\', fdeleted: objects.getValue(\''+i_uid+'.f_preload\')})');
					//h += '<div class="toolbar-item toolbar-reimport link" onclick="';
					//h += '">'+pResources.resources.toolbar.reimport+'</div>';
					
					h += pApplicationUI.toolbarItem('reimport-parent-folder', 'pMediaLibrary.reImportParentFolder({ url: \''+i_media.doc_url+'\', fdeleted: objects.getValue(\''+i_uid+'.f_preload\')})');
					//h += '<div class="toolbar-item toolbar-reimport-parent-folder link" onclick="';
					//h += '">'+pResources.resources.toolbar.reimportParentFolder+'</div>';
	
					h += pApplicationUI.toolbarItem('rename-parent-folder', 'pMediaLibrary.renameParentFolder({ url: \''+i_media.doc_url+'\', name: ' + ((i_media.file && i_media.file.parent && i_media.file.parent.name)? '\''+i_media.file.parent.name.replace(/\'/g, '\\\'')+'\'':'null') +', fdeleted: objects.getValue(\''+i_uid+'.f_preload\')})');
					//h += '<div class="toolbar-item toolbar-rename-parent-folder link" onclick="';
					//h += '">'+pResources.resources.toolbar.renameParentFolder+'</div>';
				}
			}

			if (i_lid == 'movies.medias' || i_lid == 'tvshows.episodes') {
				h += pApplicationUI.toolbarItem('find-metadata', 'pMediaLibrary.findMetadata(\''+i_media.doc_url+'\'' + 
					((p_request && p_request.xid_prefix)? ', \''+p_request.xid_prefix+'\'':', undefined') +
					((p_request && p_request.mlid)? ', \''+p_request.mlid+'\'':', undefined') +
					')');
				//h += '<div class="toolbar-item toolbar-find-metadata link" onclick="';
				//h += 'pMediaLibrary.findMetadata(\''+i_media.doc_url+'\'';
				//h += ((p_request && p_request.xid_prefix)? ', \''+p_request.xid_prefix+'\'':', undefined');
				//h += ((p_request && p_request.mlid)? ', \''+p_request.mlid+'\'':', undefined');
				//h += ')">'+pResources.resources.toolbar.findMetadata+'</div>';
			}

			//TODO:hide that
			//if (i_lid == 'movies.medias')
			//	h += '<div class="toolbar-item toolbar-set-actors link" onclick="pMediaLibrary.selectActors(\''+i_media.doc_url+'\')">'+pResources.resources.toolbar.setActors+'</div>';

			//*** PROPERTIES
			h += pApplicationUI.toolbarItem('file-properties', 'pResources.fileProperties(\''+i_media.doc_url+'\')');
			//h += '<div class="toolbar-item toolbar-properties link" onclick="pResources.fileProperties(\''+i_media.doc_url+'\')">'+pResources.resources.fileProperties_title+'</div>';
			
			if (!i_media.unavailable && !i_media.provided) {
				//*** OPTIMIZE FILE
				if (i_media.mime == "video/mp4")
					h += pApplicationUI.toolbarItem('optimize-file', 'pMediaLibrary.optimizeFile({ url: \''+i_media.doc_url+'\'}).then(objects.getValue(\''+i_uid+'.f_preload\'))');
					//h += '<div class="toolbar-item toolbar-convert link" '+(pApplicationUI.OPTION_TOOLS_CONVERT? '':'style="display: none;"')+' onclick="pMediaLibrary.convertToMP4({ url: \''+i_media.doc_url+'\', audio:'+(vc<1)+' }).then(objects.getValue(\''+i_uid+'.f_preload\'))">Convert...</div>';
				
				//*** CONVERT
				var vc = pTrackListUtil.countVideoTracks(i_tracks);
				if (vc<2 && pTrackListUtil.countAudioTracks(i_tracks)<=1)
					h += pApplicationUI.toolbarItem('convert', 'pMediaLibrary.convertToMP4({ url: \''+i_media.doc_url+'\', audio:'+(vc<1)+' }).then(objects.getValue(\''+i_uid+'.f_preload\'))', null, null, pApplicationUI.OPTION_TOOLS_CONVERT? '':'display: none;');
					//h += '<div class="toolbar-item toolbar-convert link" '+(pApplicationUI.OPTION_TOOLS_CONVERT? '':'style="display: none;"')+' onclick="pMediaLibrary.convertToMP4({ url: \''+i_media.doc_url+'\', audio:'+(vc<1)+' }).then(objects.getValue(\''+i_uid+'.f_preload\'))">Convert...</div>';
				
				//*** OPTIMIZE
				if (i_media.hasVideo)
					h += pApplicationUI.toolbarItem('optimize-video', 'pMoviePlaylist.play({ id: \''+p_request_id+'\' }, true, [ pMoviePlaylist.getCached(\''+i_media.doc_url+'\') ], true)');
					//h += '<div class="toolbar-item toolbar-optimize-video link" onclick="">Optimize...</div>';
			}

			//*** COPY
			if (i_media.provided == true && i_media.url) {
				
			}
			else {
				if (!i_media.unavailable)
					h += pApplicationUI.toolbarItem('copy', 'pMediaLibrary.copy(\''+i_media.doc_url+'\')');
					//h += '<div class="toolbar-item toolbar-copy link" onclick="pMediaLibrary.copy(\''+i_media.doc_url+'\')">'+pDocument.getStyleValue('button-copy')+'</div>';
			}
			
		}//if (pResources.get('admin') == 'true') {

		//*** DOWNLOAD
		if (''+pResources.get("canDownload")=="true" || pResources.get('admin') == 'true')
			if (!i_media.unavailable)
				if (i_media.provided!=true)
					h += pApplicationUI.toolbarItem('download', 'pMediaLibrary.download(\''+i_media.doc_url+'\')');

		//*** MORE
		h += pApplicationUI.toolbarItem('more', 'pApplicationMenu.menu(\''+i_id+'-toolbar\')');
		//h += '<div class="toolbar-item toolbar-more link" onclick="">'+pResources.resources.toolbar.more+'</div>';

		h += '</div></div>';
	}

	return h + '</div>';
}

function getVLCPlugin() {
	return false;//navigator.plugins['VLC Web Plugin'];
}

/******************************************************************************/
/***  END OF PAGE  ************************************************************/
/******************************************************************************/