001 package railo.runtime.tag; 002 003 004 import java.awt.Color; 005 import java.io.IOException; 006 import java.util.ArrayList; 007 import java.util.Iterator; 008 import java.util.List; 009 import java.util.Map; 010 import java.util.Map.Entry; 011 012 import org.apache.commons.collections.map.ReferenceMap; 013 014 import railo.commons.color.ColorCaster; 015 import railo.commons.io.res.Resource; 016 import railo.commons.io.res.type.file.FileResource; 017 import railo.commons.lang.StringUtil; 018 import railo.runtime.PageContext; 019 import railo.runtime.PageSource; 020 import railo.runtime.exp.ApplicationException; 021 import railo.runtime.exp.ExpressionException; 022 import railo.runtime.exp.PageException; 023 import railo.runtime.ext.tag.BodyTagSupport; 024 import railo.runtime.functions.string.JSStringFormat; 025 import railo.runtime.op.Caster; 026 import railo.runtime.op.Decision; 027 import railo.runtime.type.Collection.Key; 028 import railo.runtime.type.Struct; 029 import railo.runtime.video.VideoInput; 030 import railo.runtime.video.VideoInputImpl; 031 import railo.runtime.video.VideoUtilImpl; 032 033 /** 034 * implementation of the tag Compiler 035 */ 036 public class VideoPlayerJW extends BodyTagSupport { 037 038 private static final int TYPE_NONE = 0; 039 private static final int TYPE_PLAYLIST = 1; 040 private static final int TYPE_CHAPTERS = 2; 041 042 private static final int PLAYLIST_NONE = 0; 043 private static final int PLAYLIST_RIGHT = 1; 044 private static final int PLAYLIST_BOTTOM = 2; 045 046 private static Color BG_COLOR=new Color(51,51,51); 047 private static Color FG_COLOR=new Color(198,198,198); 048 049 private String video=null; 050 private boolean autostart=false; 051 052 private railo.runtime.video.Range showPlay=railo.runtime.video.Range.TRUE; 053 private railo.runtime.video.Range showPause=railo.runtime.video.Range.TRUE; 054 private railo.runtime.video.Range showTimeline=railo.runtime.video.Range.TRUE; 055 private List params=new ArrayList(); 056 private java.awt.Color bgcolor=BG_COLOR; 057 private java.awt.Color fgcolor=FG_COLOR; 058 private java.awt.Color screencolor=null; 059 private java.awt.Color lightcolor=null; 060 061 062 063 private int width=-1; 064 private int height=-1; 065 private boolean debug; 066 private boolean allowfullscreen; 067 private String strWidth; 068 private String strHeight; 069 private static Map sizes=new ReferenceMap(ReferenceMap.SOFT,ReferenceMap.SOFT); 070 071 // JW 072 private Struct passthrough=null; 073 private String preview; 074 075 private boolean group=false; 076 private boolean playlistThumbnails=true; 077 private int playlistSize=-1; 078 private int playlist=PLAYLIST_NONE; 079 private String target="_self"; 080 private boolean linkfromdisplay; 081 private String overstretch; 082 private boolean download; 083 private String id; 084 private String align; 085 private static int _id=0; 086 087 public VideoPlayerJW() { 088 089 } 090 091 @Override 092 public void release() { 093 super.release(); 094 video=null; 095 autostart=false; 096 097 showPlay=railo.runtime.video.Range.TRUE; 098 showPause=railo.runtime.video.Range.TRUE; 099 showTimeline=railo.runtime.video.Range.TRUE; 100 params.clear(); 101 debug=false; 102 103 id=null; 104 group=false; 105 playlist = PLAYLIST_NONE; 106 playlistSize=-1; 107 playlistThumbnails=true; 108 target="_self"; 109 linkfromdisplay=false; 110 overstretch=null; 111 /*group="yes" 112 playlist="right,bottom,none" 113 playlistSize="300" 114 playlistThumbnails="300" 115 116 */ 117 align=null; 118 119 120 bgcolor=BG_COLOR; 121 fgcolor=FG_COLOR; 122 screencolor=null; 123 lightcolor=null; 124 width=-1; 125 height=-1; 126 127 strWidth=null; 128 strHeight=null; 129 130 // JW 131 passthrough=null; 132 preview=null; 133 allowfullscreen=false; 134 download=false; 135 } 136 137 138 139 protected void setParam(VideoPlayerParamBean param) { 140 params.add(param); 141 } 142 143 /** 144 * @param video the video to set 145 */ 146 public void setVideo(String video) { 147 this.video = video; 148 } 149 150 /** 151 * @param autostart the autostart to set 152 */ 153 public void setAutostart(boolean autostart) { 154 this.autostart = autostart; 155 } 156 157 /** 158 * @param showPlay the showPlay to set 159 * @throws PageException 160 */ 161 public void setShowplay(String showPlay) throws PageException { 162 this.showPlay = railo.runtime.video.Range.toRange(showPlay); 163 } 164 public void setId(String id) throws PageException { 165 this.id=Caster.toVariableName(id); 166 } 167 168 /** 169 * @param showPause the showPause to set 170 * @throws PageException 171 */ 172 public void setShowpause(String showPause) throws PageException { 173 this.showPause = railo.runtime.video.Range.toRange(showPause); 174 } 175 176 /** 177 * @param showTimeline the showTimeline to set 178 * @throws PageException 179 */ 180 public void setShowtimeline(String showTimeline) throws PageException { 181 this.showTimeline = railo.runtime.video.Range.toRange(showTimeline); 182 } 183 184 /** 185 * @param color the background color to set 186 * @throws PageException 187 */ 188 public void setBgcolor(String color) throws PageException { 189 this.bgcolor = ColorCaster.toColor(color); 190 } 191 public void setBackgroundcolor(String color) throws PageException { 192 setBgcolor(color); 193 } 194 public void setBackground(String color) throws PageException { 195 setBgcolor(color); 196 } 197 public void setScreencolor(String color) throws PageException { 198 this.screencolor = ColorCaster.toColor(color); 199 } 200 public void setLightcolor(String color) throws PageException { 201 this.lightcolor = ColorCaster.toColor(color); 202 } 203 204 205 /** 206 * @param color the background color to set 207 * @throws PageException 208 */ 209 public void setFgcolor(String color) throws PageException { 210 this.fgcolor = ColorCaster.toColor(color); 211 } 212 213 public void setForeground(String color) throws PageException { 214 setFgcolor(color); 215 } 216 217 public void setForegroundcolor(String color) throws PageException { 218 setFgcolor(color); 219 } 220 221 /** 222 * @param width the width to set 223 */ 224 public void setWidth(String strWidth) { 225 this.strWidth = strWidth; 226 this.width = Caster.toIntValue(strWidth,-1); 227 } 228 229 /** 230 * @param height the height to set 231 */ 232 public void setHeight(String strHeight) { 233 this.strHeight = strHeight; 234 this.height = Caster.toIntValue(strHeight,-1); 235 } 236 237 @Override 238 public int doStartTag() throws PageException { 239 return EVAL_BODY_INCLUDE; 240 } 241 public int doEndTag() throws PageException { 242 243 // fill top video to params 244 if(video!=null) { 245 VideoPlayerParamBean vppb = new VideoPlayerParamBean(); 246 vppb.setVideo(pageContext,video); 247 if(!StringUtil.isEmpty(preview))vppb.setImage(pageContext,preview); 248 params.add(vppb); 249 } 250 else { 251 if(!StringUtil.isEmpty(preview)) 252 throw new ApplicationException("attribute [preview] is only allowed when attribute [video] is used"); 253 } 254 255 if(params.size()==0) 256 throw new ApplicationException("you have to define at least one video source"); 257 258 259 260 261 262 // calculate dimension 263 int[] dim = calculateDimension(pageContext,params,width,strWidth,height,strHeight); 264 265 //print.out(width+":"+height); 266 //print.out(strWidth+":"+strHeight); 267 width=dim[0]; 268 height=dim[1]; 269 270 //print.out(width+":"+height); 271 272 273 // playlist 274 int dspHeight=-1,dspWidth=-1; 275 if(playlist!=PLAYLIST_NONE) { 276 if(playlistSize<20)playlistSize=playlist==PLAYLIST_BOTTOM?100:200; 277 if(playlist==PLAYLIST_BOTTOM) { 278 dspHeight=height; 279 height+=playlistSize; 280 } 281 else { 282 dspWidth=width; 283 width+=playlistSize; 284 } 285 } 286 else playlistThumbnails=false; 287 288 289 VideoPlayerParamBean param; 290 291 292 String id=getId();// 293 String placeholderId="ph_"+id; 294 String flashId="swf_"+id; 295 296 StringBuffer sb=new StringBuffer(); 297 298 write(sb,"<script type=\"text/javascript\" src=\"/railo-context/swfobject.js.cfm\"></script>"); 299 write(sb,"<div "); 300 301 302 if(passthrough!=null) { 303 Iterator<Entry<Key, Object>> it = passthrough.entryIterator(); 304 Entry<Key, Object> e; 305 String key; 306 while(it.hasNext()) { 307 e = it.next(); 308 key=e.getKey().getString(); 309 if(StringUtil.startsWithIgnoreCase(key, "div.")) 310 write(sb,key.substring(4)+"=\""+Caster.toString(e.getValue())+"\" "); 311 } 312 } 313 write(sb,(align!=null?"align=\""+align+"\"":"")+" id=\""+placeholderId+"\"><a href=\"http://www.macromedia.com/go/getflashplayer\">Get the Flash Player</a> to see this player.</a></div>"); 314 315 316 317 write(sb,"<script type=\"text/javascript\">\n"); 318 write(sb,"var so = new SWFObject(\"/railo-context/mediaplayer.swf.cfm\", \""+flashId+"\", \""+width+"\", \""+(height)+"\", \"8\", \""+format("#",bgcolor)+"\");\n"); 319 320 // script 321 addParam(sb,"allowscriptaccess","always"); 322 addVariable(sb,"enablejs","true"); 323 addVariable(sb,"javascriptid",flashId); 324 325 addVariable(sb,"shuffle","false"); 326 addVariable(sb,"linktarget",target); 327 addVariable(sb,"linkfromdisplay",Caster.toString(linkfromdisplay)); 328 addVariable(sb,"abouttxt","Railo Video Player"); 329 addVariable(sb,"aboutlnk","http://www.getrailo.org"); 330 331 // control 332 addParam(sb,"allowfullscreen",Caster.toString(allowfullscreen)); 333 addParam(sb,"usefullscreen",Caster.toString(allowfullscreen)); 334 addVariable(sb,"autostart",Caster.toString(autostart)); 335 if(!StringUtil.isEmpty(overstretch))addVariable(sb,"overstretch",overstretch); 336 addVariable(sb,"showdownload",Caster.toString(download)); 337 338 339 340 341 // color 342 if(lightcolor==null)lightcolor=fgcolor.brighter(); 343 if(screencolor==null)screencolor=Color.BLACK;//fgcolor.brighter(); 344 addVariable(sb,"backcolor",format("0x",bgcolor)); 345 addVariable(sb,"frontcolor",format("0x",fgcolor)); 346 addVariable(sb,"lightcolor",format("0x",lightcolor)); 347 addVariable(sb,"screencolor",format("0x",screencolor)); 348 349 if(passthrough!=null) { 350 Iterator<Entry<Key, Object>> it = passthrough.entryIterator(); 351 Entry<Key, Object> e; 352 String key; 353 while(it.hasNext()) { 354 e = it.next(); 355 key=e.getKey().getString(); 356 if(StringUtil.startsWithIgnoreCase(key, "param.")) 357 addParam(sb,key.substring(6),Caster.toString(e.getValue())); 358 else if(StringUtil.startsWithIgnoreCase(key, "variable.")) 359 addVariable(sb,key.substring(9),Caster.toString(e.getValue())); 360 else if(StringUtil.startsWithIgnoreCase(key, "div.")); 361 else 362 addVariable(sb,key,Caster.toString(e.getValue())); 363 } 364 } 365 366 if(params.size()>1 && group) addVariable(sb,"repeat","true"); 367 368 /*if(playlist!=PLAYLIST_NONE) { 369 if(playlistSize<20)playlistSize=playlist==PLAYLIST_BOTTOM?300:200; 370 if(playlist==PLAYLIST_BOTTOM) { 371 addVariable(sb,"displayheight",Caster.toString(height)); 372 height+=playlistSize; 373 } 374 else { 375 addVariable(sb,"displaywidth",Caster.toString(width)); 376 width+=playlistSize; 377 } 378 if(playlistThumbnails && hasImages())addVariable(sb,"thumbsinplaylist","true"); 379 }*/ 380 381 // dimension 382 if(dspWidth>0)addVariable(sb,"displaywidth",Caster.toString(dspWidth)); 383 if(dspHeight>0)addVariable(sb,"displayheight",Caster.toString(dspHeight)); 384 addVariable(sb,"width",Caster.toString(width)); 385 addVariable(sb,"height",Caster.toString(height)); 386 if(playlistThumbnails && hasImages())addVariable(sb,"thumbsinplaylist","true"); 387 388 //if(preview!=null) addVariable(sb,"image",toPath(preview)); 389 //Iterator it = params.iterator(); 390 //addVariable("file","/rvp/videos/David.flv"); 391 //addVariable("captions","http://localhost:8080/caption.cfm"); 392 //while(it.hasNext()) { 393 //param=(VideoPlayerParamBean) it.next(); 394 //addVariable(sb,"file",toPath(param.getResource())); 395 //break; 396 //} 397 //addVariable("image","video.jpg"); 398 399 write(sb,"so.write(\""+placeholderId+"\");\n"); 400 //if(params.size()>1) { 401 Iterator it = params.iterator(); 402 while(it.hasNext()) { 403 param=(VideoPlayerParamBean) it.next(); 404 addItem(sb,flashId,param); 405 } 406 //} 407 write(sb,"</script>"); 408 try { 409 if(debug) { 410 pageContext.forceWrite("<pre>"+StringUtil.replace(sb.toString(), "<", "<", false)+"</pre>"); 411 } 412 pageContext.forceWrite(sb.toString()); 413 414 415 } 416 catch (IOException e) { 417 418 } 419 return EVAL_PAGE; 420 } 421 422 private synchronized String getId() { 423 if(!StringUtil.isEmpty(id)) return id; 424 _id++; 425 if(_id<0) _id=1; 426 return ""+_id; 427 } 428 429 private boolean hasImages() { 430 Iterator it = params.iterator(); 431 while(it.hasNext()) { 432 if(((VideoPlayerParamBean) it.next()).getImage()!=null) return true; 433 } 434 return false; 435 } 436 437 private void addItem(StringBuffer sb, String id, VideoPlayerParamBean param) { 438 //sb.append("setTimeout('thisMovie(\""+id+"\").addItem({file:\""+JSStringFormat.invoke(path)+"\"},null);',1000);\n"); 439 440 // file 441 String file = "file:'"+JSStringFormat.invoke(toPath(param.getResource()))+"'"; 442 443 // image 444 String image=""; 445 if(param.getImage()!=null) { 446 image=",image:'"+JSStringFormat.invoke(toPath(param.getImage()))+"'"; 447 } 448 449 // title 450 String title=""; 451 if(!StringUtil.isEmpty(param.getTitle())) { 452 title=",title:'"+JSStringFormat.invoke(param.getTitle())+"'"; 453 } 454 455 // link 456 String link=""; 457 if(!StringUtil.isEmpty(param.getLink())) { 458 link=",link:'"+JSStringFormat.invoke(param.getLink())+"'"; 459 } 460 461 // author 462 String author=""; 463 if(!StringUtil.isEmpty(param.getAuthor())) { 464 author=",author:'"+JSStringFormat.invoke(param.getAuthor())+"'"; 465 } 466 467 sb.append("addItem('"+id+"',{"+file+title+image+link+author+"});\n"); 468 } 469 470 private void addVariable(StringBuffer sb, String name, String value) { 471 value=JSStringFormat.invoke(value); 472 if(!(value.equals("false") || value.equals("true"))) 473 value="'"+value+"'"; 474 sb.append("so.addVariable('"+JSStringFormat.invoke(name)+"',"+value+");\n"); 475 } 476 477 private void addParam(StringBuffer sb,String name, String value) { 478 sb.append("so.addParam('"+name+"','"+value+"');\n"); 479 } 480 481 private static int[] calculateDimension(PageContext pc,List params,int width, String strWidth,int height, String strHeight) throws PageException { 482 Iterator it = params.iterator(); 483 ArrayList sources=new ArrayList(); 484 //Resource[] sources=new Resource[params.size()]; 485 VideoPlayerParamBean param; 486 487 while(it.hasNext()) { 488 param = (VideoPlayerParamBean) it.next(); 489 if(param.getVideo()!=null) 490 sources.add(new VideoInputImpl(param.getVideo())); 491 } 492 return VideoUtilImpl.getInstance().calculateDimension(pc, (VideoInput[])sources.toArray(new VideoInput[sources.size()]), width, strWidth, height, strHeight); 493 494 } 495 496 private String toPath(Resource res) { 497 if(!(res instanceof FileResource)) return res.getAbsolutePath(); 498 499 //Config config=pageContext.getConfig(); 500 PageSource ps = pageContext.toPageSource(res,null); 501 if(ps==null) return res.getAbsolutePath(); 502 503 String realPath = ps.getRealpath(); 504 realPath=realPath.replace('\\', '/'); 505 if(realPath.endsWith("/"))realPath=realPath.substring(0,realPath.length()-1); 506 507 //print.out("real:"+realPath); 508 String mapping=ps.getMapping().getVirtual(); 509 mapping=mapping.replace('\\', '/'); 510 if(mapping.endsWith("/"))mapping=mapping.substring(0,mapping.length()-1); 511 512 return mapping+realPath; 513 514 515 } 516 517 518 519 private void write(StringBuffer sb, String string) { 520 sb.append(string); 521 } 522 523 524 525 private static String format(String prefix, Color color) { 526 return prefix+toHex(color.getRed())+toHex(color.getGreen())+toHex(color.getBlue()); 527 } 528 529 530 531 private static String toHex(int value) { 532 String str = Integer.toHexString(value); 533 if(str.length()==1) return "0".concat(str); 534 return str; 535 } 536 537 /** 538 * @param debug the debug to set 539 */ 540 public void setDebug(boolean debug) { 541 this.debug = debug; 542 } 543 544 /** 545 * @param passthrough the passthrough to set 546 */ 547 public void setPassthrough(Struct passthrough) { 548 this.passthrough = passthrough; 549 } 550 551 /** 552 * @param preview the preview to set 553 * @throws ExpressionException 554 */ 555 public void setPreview(String preview) { 556 this.preview = preview;//ResourceUtil.toResourceExisting(pageContext, preview); 557 } 558 559 /** 560 * @param allowfullscreen the allowfullscreen to set 561 */ 562 public void setAllowfullscreen(boolean allowfullscreen) { 563 this.allowfullscreen = allowfullscreen; 564 } 565 566 public void setAlign(String strAlign) throws ApplicationException { 567 if(StringUtil.isEmpty(strAlign)) return; 568 strAlign=strAlign.trim().toLowerCase(); 569 if("right".equals(strAlign)) this.align = "right"; 570 else if("center".equals(strAlign)) this.align = "center"; 571 else if("left".equals(strAlign)) this.align = "left"; 572 else 573 throw new ApplicationException("invalid value for attribute align ["+strAlign+"], valid values are [left,center,right]"); 574 } 575 576 /** 577 * @param group the group to set 578 */ 579 public void setGroup(boolean group) { 580 this.group = group; 581 } 582 public void setLinktarget(String target) { 583 this.target = target; 584 } 585 public void setTarget(String target) { 586 this.target = target; 587 } 588 public void setLinkfromdisplay(boolean linkfromdisplay) { 589 this.linkfromdisplay = linkfromdisplay; 590 } 591 592 /** 593 * @param playlistThumbnails the playlistThumbnails to set 594 */ 595 public void setPlaylistthumbnails(boolean playlistThumbnails) { 596 this.playlistThumbnails = playlistThumbnails; 597 } 598 public void setThumbnails(boolean playlistThumbnails) { 599 setPlaylistthumbnails(playlistThumbnails); 600 } 601 public void setThumbs(boolean playlistThumbnails) { 602 setPlaylistthumbnails(playlistThumbnails); 603 } 604 605 /** 606 * @param playlistSize the playlistSize to set 607 */ 608 public void setPlaylistsize(double playlistSize) throws ApplicationException { 609 if(playlistSize<=40) throw new ApplicationException("playlist size has to be a positive number, at least 41px"); 610 this.playlistSize = (int) playlistSize; 611 } 612 613 /** 614 * @param playlist the playlist to set 615 */ 616 public void setPlaylist(String strPlaylist) throws PageException { 617 strPlaylist=strPlaylist.trim().toLowerCase(); 618 if("right".equals(strPlaylist)) playlist=PLAYLIST_RIGHT; 619 else if("bottom".equals(strPlaylist)) playlist=PLAYLIST_BOTTOM; 620 else if("none".equals(strPlaylist)) playlist=PLAYLIST_NONE; 621 else if(Decision.isBoolean(strPlaylist)) { 622 playlist=Caster.toBooleanValue(strPlaylist)?PLAYLIST_BOTTOM:PLAYLIST_NONE; 623 } 624 else throw new ApplicationException("invalid playlist definition ["+strPlaylist+"], valid values are [right,bottom,none]"); 625 } 626 627 /** 628 * @param overstretch the overstretch to set 629 */ 630 public void setOverstretch(String overstretch) throws PageException { 631 overstretch=overstretch.trim().toLowerCase(); 632 if("fit".equals(overstretch)) overstretch="fit"; 633 else if("none".equals(overstretch)) overstretch="none"; 634 else if("proportion".equals(overstretch)) overstretch="true"; 635 else if(Decision.isBoolean(overstretch)) { 636 overstretch=Caster.toString(Caster.toBooleanValue(overstretch)); 637 } 638 else throw new ApplicationException("invalid overstretch definition ["+overstretch+"], valid values are [fit,none,true,false]"); 639 640 this.overstretch = overstretch; 641 } 642 643 /** 644 * @param download the download to set 645 */ 646 public void setDownload(boolean download) { 647 this.download = download; 648 } 649 650 }